Blame psm_stats.c

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
}