|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
This file is provided under a dual BSD/GPLv2 license. When using or
|
|
Packit |
961e70 |
redistributing this file, you may do so under either license.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
GPL LICENSE SUMMARY
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
Copyright(c) 2015 Intel Corporation.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
961e70 |
it under the terms of version 2 of the GNU General Public License as
|
|
Packit |
961e70 |
published by the Free Software Foundation.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
This program is distributed in the hope that it will be useful, but
|
|
Packit |
961e70 |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
961e70 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
961e70 |
General Public License for more details.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
Contact Information:
|
|
Packit |
961e70 |
Intel Corporation, www.intel.com
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
BSD LICENSE
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
Copyright(c) 2015 Intel Corporation.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
961e70 |
modification, are permitted provided that the following conditions
|
|
Packit |
961e70 |
are met:
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
* Redistributions of source code must retain the above copyright
|
|
Packit |
961e70 |
notice, this list of conditions and the following disclaimer.
|
|
Packit |
961e70 |
* Redistributions in binary form must reproduce the above copyright
|
|
Packit |
961e70 |
notice, this list of conditions and the following disclaimer in
|
|
Packit |
961e70 |
the documentation and/or other materials provided with the
|
|
Packit |
961e70 |
distribution.
|
|
Packit |
961e70 |
* Neither the name of Intel Corporation nor the names of its
|
|
Packit |
961e70 |
contributors may be used to endorse or promote products derived
|
|
Packit |
961e70 |
from this software without specific prior written permission.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
961e70 |
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
961e70 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
Packit |
961e70 |
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
Packit |
961e70 |
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
961e70 |
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
961e70 |
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit |
961e70 |
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit |
961e70 |
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit |
961e70 |
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
961e70 |
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Copyright (c) 2003-2014 Intel Corporation. All rights reserved. */
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
#include "psm_user.h"
|
|
Packit |
961e70 |
#include "psm_mq_internal.h"
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
struct psmi_stats_type {
|
|
Packit |
961e70 |
STAILQ_ENTRY(psmi_stats_type) next;
|
|
Packit |
961e70 |
struct psmi_stats_entry *entries;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
int num_entries;
|
|
Packit |
961e70 |
void *heading;
|
|
Packit |
961e70 |
uint32_t statstype;
|
|
Packit |
961e70 |
void *context;
|
|
Packit |
961e70 |
};
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static STAILQ_HEAD(, psmi_stats_type) psmi_stats =
|
|
Packit |
961e70 |
STAILQ_HEAD_INITIALIZER(psmi_stats);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
psm2_error_t
|
|
Packit |
961e70 |
psmi_stats_register_type(const char *heading,
|
|
Packit |
961e70 |
uint32_t statstype,
|
|
Packit |
961e70 |
const struct psmi_stats_entry *entries_i,
|
|
Packit |
961e70 |
int num_entries, void *context)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
struct psmi_stats_entry *entries;
|
|
Packit |
961e70 |
struct psmi_stats_type *type;
|
|
Packit |
961e70 |
int i;
|
|
Packit |
961e70 |
psm2_error_t err = PSM2_OK;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
entries =
|
|
Packit |
961e70 |
psmi_calloc(PSMI_EP_NONE, STATS, num_entries,
|
|
Packit |
961e70 |
sizeof(struct psmi_stats_entry));
|
|
Packit |
961e70 |
type =
|
|
Packit |
961e70 |
psmi_calloc(PSMI_EP_NONE, STATS, 1, sizeof(struct psmi_stats_type));
|
|
Packit |
961e70 |
PSMI_CHECKMEM(err, entries);
|
|
Packit |
961e70 |
PSMI_CHECKMEM(err, type);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
type->entries = entries;
|
|
Packit |
961e70 |
type->num_entries = num_entries;
|
|
Packit |
961e70 |
type->statstype = statstype;
|
|
Packit |
961e70 |
type->context = context;
|
|
Packit |
961e70 |
type->heading = (char *)heading;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
for (i = 0; i < num_entries; i++) {
|
|
Packit |
961e70 |
type->entries[i].desc = entries_i[i].desc;
|
|
Packit |
961e70 |
type->entries[i].flags = entries_i[i].flags;
|
|
Packit |
961e70 |
type->entries[i].getfn = entries_i[i].getfn;
|
|
Packit |
961e70 |
type->entries[i].u.val = entries_i[i].u.val;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
STAILQ_INSERT_TAIL(&psmi_stats, type, next);
|
|
Packit |
961e70 |
return err;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
fail:
|
|
Packit |
961e70 |
if (entries)
|
|
Packit |
961e70 |
psmi_free(entries);
|
|
Packit |
961e70 |
if (type)
|
|
Packit |
961e70 |
psmi_free(type);
|
|
Packit |
961e70 |
return err;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
psm2_error_t psmi_stats_deregister_all(void)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
struct psmi_stats_type *type;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Currently our mpi still reads stats after finalize so this isn't safe
|
|
Packit |
961e70 |
* yet */
|
|
Packit |
961e70 |
while ((type = STAILQ_FIRST(&psmi_stats)) != NULL) {
|
|
Packit |
961e70 |
STAILQ_REMOVE_HEAD(&psmi_stats, next);
|
|
Packit |
961e70 |
psmi_free(type->entries);
|
|
Packit |
961e70 |
psmi_free(type);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
return PSM2_OK;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static uint32_t typestring_to_type(const char *typestr)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
if (strncasecmp(typestr, "all", 4) == 0)
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_ALL;
|
|
Packit |
961e70 |
else if (strncasecmp(typestr, "p2p", 4) == 0)
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_P2P;
|
|
Packit |
961e70 |
else if (strncasecmp(typestr, "hfi", 6) == 0)
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_HFI;
|
|
Packit |
961e70 |
else if (strncasecmp(typestr, "ips", 4) == 0)
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_IPSPROTO;
|
|
Packit |
961e70 |
else if ((strncasecmp(typestr, "intr", 5) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "thread", 7) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "rcvthread", 10) == 0))
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_RCVTHREAD;
|
|
Packit |
961e70 |
else if ((strncasecmp(typestr, "mq", 3) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "mpi", 4) == 0))
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_MQ;
|
|
Packit |
961e70 |
else if ((strncasecmp(typestr, "tid", 4) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "tids", 5) == 0))
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_TIDS;
|
|
Packit |
961e70 |
else if ((strncasecmp(typestr, "counter", 8) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "counters", 9) == 0))
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_DEVCOUNTERS;
|
|
Packit |
961e70 |
else if (strncasecmp(typestr, "devstats", 9) == 0)
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_DEVSTATS;
|
|
Packit |
961e70 |
else if ((strncasecmp(typestr, "memory", 7) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "alloc", 6) == 0) ||
|
|
Packit |
961e70 |
(strncasecmp(typestr, "malloc", 7) == 0))
|
|
Packit |
961e70 |
return PSMI_STATSTYPE_MEMORY;
|
|
Packit |
961e70 |
else
|
|
Packit |
961e70 |
return 0;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static uint32_t stats_parse_enabled_mask(const char *stats_string)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
char *b = (char *)stats_string;
|
|
Packit |
961e70 |
char *e = b;
|
|
Packit |
961e70 |
char buf[128];
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
uint32_t stats_enabled_mask = 0;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
while (*e) {
|
|
Packit |
961e70 |
b = e;
|
|
Packit |
961e70 |
while (*e && *e != ',' && *e != '+' && *e != '.' &&
|
|
Packit |
961e70 |
*e != '|' && *e != ':')
|
|
Packit |
961e70 |
e++;
|
|
Packit |
961e70 |
if (e > b) { /* something new to parse */
|
|
Packit |
961e70 |
int len = ((e - b) > (sizeof(buf) - 1)) ?
|
|
Packit |
961e70 |
(sizeof(buf) - 1) : (e - b);
|
|
Packit |
961e70 |
strncpy(buf, b, len);
|
|
Packit |
961e70 |
buf[len] = '\0';
|
|
Packit |
961e70 |
stats_enabled_mask |= typestring_to_type(buf);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
if (*e)
|
|
Packit |
961e70 |
e++; /* skip delimiter */
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
return stats_enabled_mask;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
void psmi_stats_mpspawn_callback(struct mpspawn_stats_req_args *args)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
const struct psmi_stats_entry *entry;
|
|
Packit |
961e70 |
struct psmi_stats_type *type = (struct psmi_stats_type *)args->context;
|
|
Packit |
961e70 |
int i, num = args->num;
|
|
Packit |
961e70 |
uint64_t *stats = args->stats;
|
|
Packit |
961e70 |
uint64_t *c = NULL;
|
|
Packit |
961e70 |
uint64_t *s = NULL;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
psmi_assert(num == type->num_entries);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
if (type->statstype == PSMI_STATSTYPE_DEVCOUNTERS ||
|
|
Packit |
961e70 |
type->statstype == PSMI_STATSTYPE_DEVSTATS) {
|
|
Packit |
961e70 |
int unit_id = ((psm2_ep_t) type->context)->unit_id;
|
|
Packit |
961e70 |
int portno = ((psm2_ep_t) type->context)->portnum;
|
|
Packit |
961e70 |
uintptr_t off;
|
|
Packit |
961e70 |
uint8_t *p = NULL;
|
|
Packit |
961e70 |
int nc, npc, ns;
|
|
Packit |
961e70 |
int nstats = hfi_get_stats_names_count();
|
|
Packit |
961e70 |
int nctrs = hfi_get_ctrs_unit_names_count(unit_id);
|
|
Packit |
961e70 |
int npctrs = hfi_get_ctrs_port_names_count(unit_id);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
if (nctrs != -1 && npctrs != -1)
|
|
Packit |
961e70 |
c = psmi_calloc(PSMI_EP_NONE, STATS, nctrs + npctrs,
|
|
Packit |
961e70 |
sizeof(uint64_t));
|
|
Packit |
961e70 |
if (nstats != -1)
|
|
Packit |
961e70 |
s = psmi_calloc(PSMI_EP_NONE, STATS, nstats,
|
|
Packit |
961e70 |
sizeof(uint64_t));
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* If hfifs is not loaded, we set NAN everywhere. We don't want
|
|
Packit |
961e70 |
* stats to break just because 1 node didn't have hfi-stats
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
if (type->statstype == PSMI_STATSTYPE_DEVCOUNTERS && c != NULL) {
|
|
Packit |
961e70 |
nc = hfi_get_ctrs_unit(unit_id, c, nctrs);
|
|
Packit |
961e70 |
if (nc != -1 && nc == nctrs)
|
|
Packit |
961e70 |
p = (uint8_t *) c;
|
|
Packit |
961e70 |
if (nc == -1)
|
|
Packit |
961e70 |
nc = 0;
|
|
Packit |
961e70 |
npc =
|
|
Packit |
961e70 |
hfi_get_ctrs_port(unit_id, portno, c + nc, npctrs);
|
|
Packit |
961e70 |
if (!p && npc > 0 && npc == npctrs)
|
|
Packit |
961e70 |
p = (uint8_t *) c;
|
|
Packit |
961e70 |
} else if (s != NULL) {
|
|
Packit |
961e70 |
ns = hfi_get_stats(s, nstats);
|
|
Packit |
961e70 |
if (ns != -1)
|
|
Packit |
961e70 |
p = (uint8_t *) s;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
for (i = 0; i < num; i++) {
|
|
Packit |
961e70 |
entry = &type->entries[i];
|
|
Packit |
961e70 |
if (p) {
|
|
Packit |
961e70 |
off = (uintptr_t) entry->u.off;
|
|
Packit |
961e70 |
stats[i] = *((uint64_t *) (p + off));
|
|
Packit |
961e70 |
} else
|
|
Packit |
961e70 |
stats[i] = MPSPAWN_NAN_U64;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
} else if (type->statstype == PSMI_STATSTYPE_MEMORY) {
|
|
Packit |
961e70 |
for (i = 0; i < num; i++) {
|
|
Packit |
961e70 |
entry = &type->entries[i];
|
|
Packit |
961e70 |
stats[i] =
|
|
Packit |
961e70 |
*(uint64_t *) ((uintptr_t) &psmi_stats_memory +
|
|
Packit |
961e70 |
(uintptr_t) entry->u.off);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
} else {
|
|
Packit |
961e70 |
for (i = 0; i < num; i++) {
|
|
Packit |
961e70 |
entry = &type->entries[i];
|
|
Packit |
961e70 |
if (entry->getfn != NULL)
|
|
Packit |
961e70 |
stats[i] = entry->getfn(type->context);
|
|
Packit |
961e70 |
else
|
|
Packit |
961e70 |
stats[i] = *entry->u.val;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
if (c != NULL)
|
|
Packit |
961e70 |
psmi_free(c);
|
|
Packit |
961e70 |
if (s != NULL)
|
|
Packit |
961e70 |
psmi_free(s);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
void
|
|
Packit |
961e70 |
stats_register_mpspawn_single(mpspawn_stats_add_fn add_fn,
|
|
Packit |
961e70 |
char *heading,
|
|
Packit |
961e70 |
int num_entries,
|
|
Packit |
961e70 |
struct psmi_stats_entry *entries,
|
|
Packit |
961e70 |
mpspawn_stats_req_fn req_fn, void *context)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
int i;
|
|
Packit |
961e70 |
struct mpspawn_stats_add_args mp_add;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
mp_add.version = MPSPAWN_STATS_VERSION;
|
|
Packit |
961e70 |
mp_add.num = num_entries;
|
|
Packit |
961e70 |
mp_add.header = heading;
|
|
Packit |
961e70 |
mp_add.req_fn = req_fn;
|
|
Packit |
961e70 |
mp_add.context = context;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
mp_add.desc = (char **)alloca(sizeof(char *) * num_entries);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
mp_add.flags = (uint16_t *) alloca(sizeof(uint16_t *) * num_entries);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
for (i = 0; i < num_entries; i++) {
|
|
Packit |
961e70 |
mp_add.desc[i] = (char *)entries[i].desc;
|
|
Packit |
961e70 |
mp_add.flags[i] = entries[i].flags;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Ignore return code, doesn't matter to *us* if register failed */
|
|
Packit |
961e70 |
add_fn(&mp_add);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
return;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static void stats_register_hfi_counters(psm2_ep_t ep);
|
|
Packit |
961e70 |
static void stats_register_hfi_stats(psm2_ep_t ep);
|
|
Packit |
961e70 |
static void stats_register_mem_stats(psm2_ep_t ep);
|
|
Packit |
961e70 |
static psm2_error_t psmi_stats_epaddr_register(struct mpspawn_stats_init_args
|
|
Packit |
961e70 |
*args);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* Downcall from QLogic MPI into PSM, so we can register stats
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
void *psmi_stats_register(struct mpspawn_stats_init_args *args)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
struct psmi_stats_type *type;
|
|
Packit |
961e70 |
uint32_t statsmask;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* Args has a version string in it, but we can ignore it since mpspawn
|
|
Packit |
961e70 |
* will decide if it supports *our* version
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* Eventually, parse the stats_types to add various "flavours" of stats
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
if (args->stats_types == NULL)
|
|
Packit |
961e70 |
return NULL;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
statsmask = stats_parse_enabled_mask(args->stats_types);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* MQ (MPI-level) statistics */
|
|
Packit |
961e70 |
if (statsmask & PSMI_STATSTYPE_MQ)
|
|
Packit |
961e70 |
psmi_mq_stats_register(args->mq, args->add_fn);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* PSM and hfi level statistics */
|
|
Packit |
961e70 |
if (statsmask & PSMI_STATSTYPE_DEVCOUNTERS)
|
|
Packit |
961e70 |
stats_register_hfi_counters(args->mq->ep);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
if (statsmask & PSMI_STATSTYPE_DEVSTATS)
|
|
Packit |
961e70 |
stats_register_hfi_stats(args->mq->ep);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
if (statsmask & PSMI_STATSTYPE_MEMORY)
|
|
Packit |
961e70 |
stats_register_mem_stats(args->mq->ep);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* At this point all PSM and hfi-level components have registered stats
|
|
Packit |
961e70 |
* with the PSM stats interface. We register with the mpspawn stats
|
|
Packit |
961e70 |
* interface with an upcall in add_fn
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
STAILQ_FOREACH(type, &psmi_stats, next) {
|
|
Packit |
961e70 |
if (type->statstype & statsmask)
|
|
Packit |
961e70 |
stats_register_mpspawn_single(args->add_fn,
|
|
Packit |
961e70 |
type->heading,
|
|
Packit |
961e70 |
type->num_entries,
|
|
Packit |
961e70 |
type->entries,
|
|
Packit |
961e70 |
psmi_stats_mpspawn_callback,
|
|
Packit |
961e70 |
type);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* Special handling for per-endpoint statistics
|
|
Packit |
961e70 |
* Only MPI knows what the endpoint-addresses are in the running program,
|
|
Packit |
961e70 |
* PSM has no sense of MPI worlds. In stats register, MPI tells PSM how
|
|
Packit |
961e70 |
* many endpoints it anticipates having and PSM simply reserves that amount
|
|
Packit |
961e70 |
* of stats entries X the amount of per-endpoint stats.
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
if (statsmask & PSMI_STATSTYPE_P2P)
|
|
Packit |
961e70 |
psmi_stats_epaddr_register(args);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
return NULL;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
struct stats_epaddr {
|
|
Packit |
961e70 |
psm2_ep_t ep;
|
|
Packit |
961e70 |
mpspawn_map_epaddr_fn epaddr_map_fn;
|
|
Packit |
961e70 |
int num_ep;
|
|
Packit |
961e70 |
int num_ep_stats;
|
|
Packit |
961e70 |
};
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
void psmi_stats_epaddr_callback(struct mpspawn_stats_req_args *args)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
int i, num, off;
|
|
Packit |
961e70 |
uint64_t *statsp;
|
|
Packit |
961e70 |
struct stats_epaddr *stats_ctx = (struct stats_epaddr *)args->context;
|
|
Packit |
961e70 |
psm2_ep_t ep = stats_ctx->ep;
|
|
Packit |
961e70 |
psm2_epaddr_t epaddr;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
num = stats_ctx->num_ep * stats_ctx->num_ep_stats;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* First always NAN the entire stats request */
|
|
Packit |
961e70 |
for (i = 0; i < num; i++) {
|
|
Packit |
961e70 |
if (args->flags[i] & MPSPAWN_STATS_TYPE_DOUBLE)
|
|
Packit |
961e70 |
args->stats[i] = MPSPAWN_NAN;
|
|
Packit |
961e70 |
else
|
|
Packit |
961e70 |
args->stats[i] = MPSPAWN_NAN_U64;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
for (i = 0; i < stats_ctx->num_ep; i++) {
|
|
Packit |
961e70 |
statsp = args->stats + i * stats_ctx->num_ep_stats;
|
|
Packit |
961e70 |
off = 0;
|
|
Packit |
961e70 |
epaddr = stats_ctx->epaddr_map_fn(i);
|
|
Packit |
961e70 |
if (epaddr == NULL)
|
|
Packit |
961e70 |
continue;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Self */
|
|
Packit |
961e70 |
if (&ep->ptl_self == epaddr->ptlctl) {
|
|
Packit |
961e70 |
if (ep->ptl_self.epaddr_stats_get != NULL)
|
|
Packit |
961e70 |
off +=
|
|
Packit |
961e70 |
ep->ptl_self.epaddr_stats_get(epaddr,
|
|
Packit |
961e70 |
statsp + off);
|
|
Packit |
961e70 |
} else {
|
|
Packit |
961e70 |
if (ep->ptl_self.epaddr_stats_num != NULL)
|
|
Packit |
961e70 |
off += ep->ptl_self.epaddr_stats_num();
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Shm */
|
|
Packit |
961e70 |
if (&ep->ptl_amsh == epaddr->ptlctl) {
|
|
Packit |
961e70 |
if (ep->ptl_amsh.epaddr_stats_get != NULL)
|
|
Packit |
961e70 |
off +=
|
|
Packit |
961e70 |
ep->ptl_amsh.epaddr_stats_get(epaddr,
|
|
Packit |
961e70 |
statsp + off);
|
|
Packit |
961e70 |
} else {
|
|
Packit |
961e70 |
if (ep->ptl_amsh.epaddr_stats_num != NULL)
|
|
Packit |
961e70 |
off += ep->ptl_amsh.epaddr_stats_num();
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* ips */
|
|
Packit |
961e70 |
if (&ep->ptl_ips == epaddr->ptlctl) {
|
|
Packit |
961e70 |
if (ep->ptl_ips.epaddr_stats_get != NULL)
|
|
Packit |
961e70 |
off +=
|
|
Packit |
961e70 |
ep->ptl_ips.epaddr_stats_get(epaddr,
|
|
Packit |
961e70 |
statsp + off);
|
|
Packit |
961e70 |
} else {
|
|
Packit |
961e70 |
if (ep->ptl_ips.epaddr_stats_num != NULL)
|
|
Packit |
961e70 |
off += ep->ptl_ips.epaddr_stats_num();
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
return;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
psm2_error_t
|
|
Packit |
961e70 |
psmi_stats_epaddr_register(struct mpspawn_stats_init_args *args)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
int i = 0, j;
|
|
Packit |
961e70 |
int num_ep = args->num_epaddr;
|
|
Packit |
961e70 |
int num_ep_stats = 0;
|
|
Packit |
961e70 |
int nz;
|
|
Packit |
961e70 |
char **desc, **desc_i;
|
|
Packit |
961e70 |
uint16_t *flags, *flags_i;
|
|
Packit |
961e70 |
char *p;
|
|
Packit |
961e70 |
char buf[128];
|
|
Packit |
961e70 |
psm2_ep_t ep;
|
|
Packit |
961e70 |
struct mpspawn_stats_add_args mp_add;
|
|
Packit |
961e70 |
struct stats_epaddr *stats_ctx;
|
|
Packit |
961e70 |
psm2_error_t err = PSM2_OK;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
if (args->mq == NULL)
|
|
Packit |
961e70 |
return PSM2_OK;
|
|
Packit |
961e70 |
ep = args->mq->ep;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Figure out how many stats there are in an endpoint from all devices */
|
|
Packit |
961e70 |
if (ep->ptl_self.epaddr_stats_num != NULL)
|
|
Packit |
961e70 |
num_ep_stats += ep->ptl_self.epaddr_stats_num();
|
|
Packit |
961e70 |
if (ep->ptl_amsh.epaddr_stats_num != NULL)
|
|
Packit |
961e70 |
num_ep_stats += ep->ptl_amsh.epaddr_stats_num();
|
|
Packit |
961e70 |
if (ep->ptl_ips.epaddr_stats_num != NULL)
|
|
Packit |
961e70 |
num_ep_stats += ep->ptl_ips.epaddr_stats_num();
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Allocate desc and flags and let each device initialize their
|
|
Packit |
961e70 |
* descriptions and flags */
|
|
Packit |
961e70 |
desc =
|
|
Packit |
961e70 |
psmi_malloc(ep, STATS,
|
|
Packit |
961e70 |
sizeof(char *) * num_ep_stats * (num_ep + 1));
|
|
Packit |
961e70 |
if (desc == NULL)
|
|
Packit |
961e70 |
return PSM2_NO_MEMORY;
|
|
Packit |
961e70 |
flags =
|
|
Packit |
961e70 |
psmi_malloc(ep, STATS,
|
|
Packit |
961e70 |
sizeof(uint16_t) * num_ep_stats * (num_ep + 1));
|
|
Packit |
961e70 |
if (flags == NULL) {
|
|
Packit |
961e70 |
psmi_free(desc);
|
|
Packit |
961e70 |
return PSM2_NO_MEMORY;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/* Get the descriptions/flags from each device */
|
|
Packit |
961e70 |
i = 0;
|
|
Packit |
961e70 |
i += ep->ptl_self.epaddr_stats_num != NULL ?
|
|
Packit |
961e70 |
ep->ptl_self.epaddr_stats_init(desc + i, flags + i) : 0;
|
|
Packit |
961e70 |
i += ep->ptl_amsh.epaddr_stats_num != NULL ?
|
|
Packit |
961e70 |
ep->ptl_amsh.epaddr_stats_init(desc + i, flags + i) : 0;
|
|
Packit |
961e70 |
i += ep->ptl_ips.epaddr_stats_num != NULL ?
|
|
Packit |
961e70 |
ep->ptl_ips.epaddr_stats_init(desc + i, flags + i) : 0;
|
|
Packit |
961e70 |
psmi_assert_always(i == num_ep_stats);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
/*
|
|
Packit |
961e70 |
* Clone the descriptions for each endpoint but append "rank %d" to it
|
|
Packit |
961e70 |
* beforehand.
|
|
Packit |
961e70 |
*/
|
|
Packit |
961e70 |
nz = (num_ep < 10 ? 1 : (num_ep < 100 ? 2 : /* cheap log */
|
|
Packit |
961e70 |
(num_ep < 1000 ? 3 : (num_ep < 1000 ? 4 :
|
|
Packit |
961e70 |
(num_ep <
|
|
Packit |
961e70 |
10000 ? 5 : 6)))));
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
desc_i = desc + num_ep_stats;
|
|
Packit |
961e70 |
flags_i = flags + num_ep_stats;
|
|
Packit |
961e70 |
memset(desc_i, 0, sizeof(char *) * num_ep * num_ep_stats);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
for (i = 0; i < num_ep; i++) {
|
|
Packit |
961e70 |
for (j = 0; j < num_ep_stats; j++) {
|
|
Packit |
961e70 |
snprintf(buf, sizeof(buf) - 1, "<%*d> %s", nz, i,
|
|
Packit |
961e70 |
desc[j]);
|
|
Packit |
961e70 |
buf[sizeof(buf) - 1] = '\0';
|
|
Packit |
961e70 |
p = psmi_strdup(ep, buf);
|
|
Packit |
961e70 |
if (p == NULL) {
|
|
Packit |
961e70 |
err = PSM2_NO_MEMORY;
|
|
Packit |
961e70 |
goto clean;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
desc_i[i * num_ep_stats + j] = p;
|
|
Packit |
961e70 |
flags_i[i * num_ep_stats + j] = flags[j];
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
mp_add.version = MPSPAWN_STATS_VERSION;
|
|
Packit |
961e70 |
mp_add.num = num_ep_stats * num_ep;
|
|
Packit |
961e70 |
mp_add.header = "Endpoint-to-Endpoint Stats (by <rank>)";
|
|
Packit |
961e70 |
mp_add.req_fn = psmi_stats_epaddr_callback;
|
|
Packit |
961e70 |
mp_add.desc = desc_i;
|
|
Packit |
961e70 |
mp_add.flags = flags_i;
|
|
Packit |
961e70 |
stats_ctx = psmi_malloc(ep, STATS, sizeof(struct stats_epaddr));
|
|
Packit |
961e70 |
if (stats_ctx == NULL) {
|
|
Packit |
961e70 |
err = PSM2_NO_MEMORY;
|
|
Packit |
961e70 |
goto clean;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
stats_ctx->ep = ep;
|
|
Packit |
961e70 |
stats_ctx->epaddr_map_fn = args->epaddr_map_fn;
|
|
Packit |
961e70 |
stats_ctx->num_ep = num_ep;
|
|
Packit |
961e70 |
stats_ctx->num_ep_stats = num_ep_stats;
|
|
Packit |
961e70 |
mp_add.context = stats_ctx;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
args->add_fn(&mp_add);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
clean:
|
|
Packit |
961e70 |
/* Now we can free all the descriptions */
|
|
Packit |
961e70 |
for (i = 0; i < num_ep; i++) {
|
|
Packit |
961e70 |
for (j = 0; j < num_ep_stats; j++)
|
|
Packit |
961e70 |
if (desc_i[i * num_ep_stats + j])
|
|
Packit |
961e70 |
psmi_free(desc_i[i * num_ep_stats + j]);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
psmi_free(desc);
|
|
Packit |
961e70 |
psmi_free(flags);
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
return err;
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
void stats_register_hfi_counters(psm2_ep_t ep)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
int i, nc, npc;
|
|
Packit |
961e70 |
char *cnames = NULL, *pcnames = NULL;
|
|
Packit |
961e70 |
struct psmi_stats_entry *entries = NULL;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
nc = hfi_get_ctrs_unit_names(ep->unit_id, &cnames);
|
|
Packit |
961e70 |
if (nc == -1 || cnames == NULL)
|
|
Packit |
961e70 |
goto bail;
|
|
Packit |
961e70 |
npc = hfi_get_ctrs_port_names(ep->unit_id, &pcnames);
|
|
Packit |
961e70 |
if (npc == -1 || pcnames == NULL)
|
|
Packit |
961e70 |
goto bail;
|
|
Packit |
961e70 |
entries =
|
|
Packit |
961e70 |
psmi_calloc(ep, STATS, nc + npc, sizeof(struct psmi_stats_entry));
|
|
Packit |
961e70 |
if (entries == NULL)
|
|
Packit |
961e70 |
goto bail;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
for (i = 0; i < nc; i++) {
|
|
Packit |
961e70 |
entries[i].desc = hfi_get_next_name(&cnames);
|
|
Packit |
961e70 |
entries[i].flags = MPSPAWN_STATS_REDUCTION_ALL |
|
|
Packit |
961e70 |
MPSPAWN_STATS_SKIP_IF_ZERO;
|
|
Packit |
961e70 |
entries[i].getfn = NULL;
|
|
Packit |
961e70 |
entries[i].u.off = i * sizeof(uint64_t);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
for (i = nc; i < nc + npc; i++) {
|
|
Packit |
961e70 |
entries[i].desc = hfi_get_next_name(&pcnames);
|
|
Packit |
961e70 |
entries[i].flags = MPSPAWN_STATS_REDUCTION_ALL |
|
|
Packit |
961e70 |
MPSPAWN_STATS_SKIP_IF_ZERO;
|
|
Packit |
961e70 |
entries[i].getfn = NULL;
|
|
Packit |
961e70 |
entries[i].u.off = i * sizeof(uint64_t);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
psmi_stats_register_type("OPA device counters",
|
|
Packit |
961e70 |
PSMI_STATSTYPE_DEVCOUNTERS,
|
|
Packit |
961e70 |
entries, nc + npc, ep);
|
|
Packit Service |
7ed5cc |
// psmi_stats_register_type makes it's own copy of entries
|
|
Packit Service |
7ed5cc |
// so we should free the entries buffer.
|
|
Packit Service |
7ed5cc |
// The snames will be freed when we deregister the hfi.
|
|
Packit Service |
7ed5cc |
psmi_free(entries);
|
|
Packit |
961e70 |
return;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
bail:
|
|
Packit |
961e70 |
if (cnames != NULL)
|
|
Packit |
961e70 |
hfi_release_names(cnames);
|
|
Packit |
961e70 |
if (pcnames != NULL)
|
|
Packit |
961e70 |
hfi_release_names(pcnames);
|
|
Packit |
961e70 |
if (entries != NULL)
|
|
Packit |
961e70 |
psmi_free(entries);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
void stats_register_hfi_stats(psm2_ep_t ep)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
int i, ns;
|
|
Packit |
961e70 |
char *snames = NULL;
|
|
Packit |
961e70 |
struct psmi_stats_entry *entries = NULL;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
ns = hfi_get_stats_names(&snames);
|
|
Packit Service |
7ed5cc |
if (ns <= 0 || snames == NULL)
|
|
Packit |
961e70 |
goto bail;
|
|
Packit |
961e70 |
entries = psmi_calloc(ep, STATS, ns, sizeof(struct psmi_stats_entry));
|
|
Packit |
961e70 |
if (entries == NULL)
|
|
Packit |
961e70 |
goto bail;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
for (i = 0; i < ns; i++) {
|
|
Packit |
961e70 |
entries[i].desc = hfi_get_next_name(&snames);
|
|
Packit |
961e70 |
entries[i].flags = MPSPAWN_STATS_REDUCTION_ALL |
|
|
Packit |
961e70 |
MPSPAWN_STATS_SKIP_IF_ZERO;
|
|
Packit |
961e70 |
entries[i].getfn = NULL;
|
|
Packit |
961e70 |
entries[i].u.off = i * sizeof(uint64_t);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
psmi_stats_register_type("OPA device statistics",
|
|
Packit |
961e70 |
PSMI_STATSTYPE_DEVSTATS, entries, ns, ep);
|
|
Packit |
961e70 |
// psmi_stats_register_type makes it's own copy of entries
|
|
Packit |
961e70 |
// so we should free the entries buffer.
|
|
Packit |
961e70 |
// The snames will be freed when we deregister the hfi.
|
|
Packit |
961e70 |
psmi_free(entries);
|
|
Packit |
961e70 |
return;
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
bail:
|
|
Packit |
961e70 |
if (snames != NULL)
|
|
Packit |
961e70 |
hfi_release_names(snames);
|
|
Packit |
961e70 |
if (entries != NULL)
|
|
Packit |
961e70 |
psmi_free(entries);
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
#undef _SDECL
|
|
Packit |
961e70 |
#define _SDECL(_desc, _param) { \
|
|
Packit |
961e70 |
.desc = _desc, \
|
|
Packit |
961e70 |
.flags = MPSPAWN_STATS_REDUCTION_ALL \
|
|
Packit |
961e70 |
| MPSPAWN_STATS_SKIP_IF_ZERO, \
|
|
Packit |
961e70 |
.getfn = NULL, \
|
|
Packit |
961e70 |
.u.off = offsetof(struct psmi_stats_malloc, _param) \
|
|
Packit |
961e70 |
}
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
static
|
|
Packit |
961e70 |
void stats_register_mem_stats(psm2_ep_t ep)
|
|
Packit |
961e70 |
{
|
|
Packit |
961e70 |
struct psmi_stats_entry entries[] = {
|
|
Packit |
961e70 |
_SDECL("Total (current)", m_all_total),
|
|
Packit |
961e70 |
_SDECL("Total (max)", m_all_max),
|
|
Packit |
961e70 |
_SDECL("All Peers (current)", m_perpeer_total),
|
|
Packit |
961e70 |
_SDECL("All Peers (max)", m_perpeer_max),
|
|
Packit |
961e70 |
_SDECL("Network Buffers (current)", m_netbufs_total),
|
|
Packit |
961e70 |
_SDECL("Network Buffers (max)", m_netbufs_max),
|
|
Packit |
961e70 |
_SDECL("PSM desctors (current)", m_descriptors_total),
|
|
Packit |
961e70 |
_SDECL("PSM desctors (max)", m_descriptors_max),
|
|
Packit |
961e70 |
_SDECL("Unexp. buffers (current)", m_unexpbufs_total),
|
|
Packit |
961e70 |
_SDECL("Unexp. Buffers (max)", m_unexpbufs_max),
|
|
Packit |
961e70 |
_SDECL("Other (current)", m_undefined_total),
|
|
Packit |
961e70 |
_SDECL("Other (max)", m_undefined_max),
|
|
Packit |
961e70 |
};
|
|
Packit |
961e70 |
|
|
Packit |
961e70 |
psmi_stats_register_type("PSM memory allocation statistics",
|
|
Packit |
961e70 |
PSMI_STATSTYPE_MEMORY,
|
|
Packit |
961e70 |
entries, PSMI_STATS_HOWMANY(entries), ep);
|
|
Packit |
961e70 |
}
|