1/* 2 * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3 * Copyright (c) 2007 Xsigo Systems Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 * 33 */ 34 35#if HAVE_CONFIG_H 36# include <config.h> 37#endif /* HAVE_CONFIG_H */ 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <unistd.h> 42#include <stdarg.h> 43#include <getopt.h> 44#include <netinet/in.h> 45 46#include <infiniband/common.h> 47#include <infiniband/umad.h> 48#include <infiniband/mad.h> 49 50#include "ibdiag_common.h" 51 52struct perf_count { 53 uint32_t portselect; 54 uint32_t counterselect; 55 uint32_t symbolerrors; 56 uint32_t linkrecovers; 57 uint32_t linkdowned; 58 uint32_t rcverrors; 59 uint32_t rcvremotephyerrors; 60 uint32_t rcvswrelayerrors; 61 uint32_t xmtdiscards; 62 uint32_t xmtconstrainterrors; 63 uint32_t rcvconstrainterrors; 64 uint32_t linkintegrityerrors; 65 uint32_t excbufoverrunerrors; 66 uint32_t vl15dropped; 67 uint32_t xmtdata; 68 uint32_t rcvdata; 69 uint32_t xmtpkts; 70 uint32_t rcvpkts; 71}; 72 73struct perf_count_ext { 74 uint32_t portselect; 75 uint32_t counterselect; 76 uint64_t portxmitdata; 77 uint64_t portrcvdata; 78 uint64_t portxmitpkts; 79 uint64_t portrcvpkts; 80 uint64_t portunicastxmitpkts; 81 uint64_t portunicastrcvpkts; 82 uint64_t portmulticastxmitpkits; 83 uint64_t portmulticastrcvpkts; 84}; 85 86static uint8_t pc[1024]; 87 88struct perf_count perf_count = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 89struct perf_count_ext perf_count_ext = {0,0,0,0,0,0,0,0,0,0}; 90 91char *argv0 = "perfquery"; 92 93#define ALL_PORTS 0xFF 94 95static void 96usage(void) 97{ 98 char *basename; 99 100 if (!(basename = strrchr(argv0, '/'))) 101 basename = argv0; 102 else 103 basename++; 104 105 fprintf(stderr, "Usage: %s [-d(ebug) -G(uid) -a(ll_ports) -l(oop_ports) -r(eset_after_read) -C ca_name -P ca_port " 106 "-R(eset_only) -t(imeout) timeout_ms -V(ersion) -h(elp)] [<lid|guid> [[port] [reset_mask]]]\n", 107 basename); 108 fprintf(stderr, "\tExamples:\n"); 109 fprintf(stderr, "\t\t%s\t\t# read local port's performance counters\n", basename); 110 fprintf(stderr, "\t\t%s 32 1\t\t# read performance counters from lid 32, port 1\n", basename); 111 fprintf(stderr, "\t\t%s -e 32 1\t# read extended performance counters from lid 32, port 1\n", basename); 112 fprintf(stderr, "\t\t%s -a 32\t\t# read performance counters from lid 32, all ports\n", basename); 113 fprintf(stderr, "\t\t%s -r 32 1\t# read performance counters and reset\n", basename); 114 fprintf(stderr, "\t\t%s -e -r 32 1\t# read extended performance counters and reset\n", basename); 115 fprintf(stderr, "\t\t%s -R 0x20 1\t# reset performance counters of port 1 only\n", basename); 116 fprintf(stderr, "\t\t%s -e -R 0x20 1\t# reset extended performance counters of port 1 only\n", basename); 117 fprintf(stderr, "\t\t%s -R -a 32\t# reset performance counters of all ports\n", basename); 118 fprintf(stderr, "\t\t%s -R 32 2 0x0fff\t# reset only error counters of port 2\n", basename); 119 fprintf(stderr, "\t\t%s -R 32 2 0xf000\t# reset only non-error counters of port 2\n", basename); 120 exit(-1); 121} 122 123/* Notes: IB semantics is to cap counters if count has exceeded limits. 124 * Therefore we must check for overflows and cap the counters if necessary. 125 * 126 * mad_decode_field and mad_encode_field assume 32 bit integers passed in 127 * for fields < 32 bits in length. 128 */ 129 130static void aggregate_4bit(uint32_t *dest, uint32_t val) 131{ 132 if ((((*dest) + val) < (*dest)) 133 || ((*dest) + val) > 0xf) 134 (*dest) = 0xf; 135 else 136 (*dest) = (*dest) + val; 137} 138 139static void aggregate_8bit(uint32_t *dest, uint32_t val) 140{ 141 if ((((*dest) + val) < (*dest)) 142 || ((*dest) + val) > 0xff) 143 (*dest) = 0xff; 144 else 145 (*dest) = (*dest) + val; 146} 147 148static void aggregate_16bit(uint32_t *dest, uint32_t val) 149{ 150 if ((((*dest) + val) < (*dest)) 151 || ((*dest) + val) > 0xffff) 152 (*dest) = 0xffff; 153 else 154 (*dest) = (*dest) + val; 155} 156 157static void aggregate_32bit(uint32_t *dest, uint32_t val) 158{ 159 if (((*dest) + val) < (*dest)) 160 (*dest) = 0xffffffff; 161 else 162 (*dest) = (*dest) + val; 163} 164 165static void aggregate_64bit(uint64_t *dest, uint64_t val) 166{ 167 if (((*dest) + val) < (*dest)) 168 (*dest) = 0xffffffffffffffffULL; 169 else 170 (*dest) = (*dest) + val; 171} 172 173static void aggregate_perfcounters(void) 174{ 175 uint32_t val; 176 177 mad_decode_field(pc, IB_PC_PORT_SELECT_F, &val); 178 perf_count.portselect = val; 179 mad_decode_field(pc, IB_PC_COUNTER_SELECT_F, &val); 180 perf_count.counterselect = val; 181 mad_decode_field(pc, IB_PC_ERR_SYM_F, &val); 182 aggregate_16bit(&perf_count.symbolerrors, val); 183 mad_decode_field(pc, IB_PC_LINK_RECOVERS_F, &val); 184 aggregate_8bit(&perf_count.linkrecovers, val); 185 mad_decode_field(pc, IB_PC_LINK_DOWNED_F, &val); 186 aggregate_8bit(&perf_count.linkdowned, val); 187 mad_decode_field(pc, IB_PC_ERR_RCV_F, &val); 188 aggregate_16bit(&perf_count.rcverrors, val); 189 mad_decode_field(pc, IB_PC_ERR_PHYSRCV_F, &val); 190 aggregate_16bit(&perf_count.rcvremotephyerrors, val); 191 mad_decode_field(pc, IB_PC_ERR_SWITCH_REL_F, &val); 192 aggregate_16bit(&perf_count.rcvswrelayerrors, val); 193 mad_decode_field(pc, IB_PC_XMT_DISCARDS_F, &val); 194 aggregate_16bit(&perf_count.xmtdiscards, val); 195 mad_decode_field(pc, IB_PC_ERR_XMTCONSTR_F, &val); 196 aggregate_8bit(&perf_count.xmtconstrainterrors, val); 197 mad_decode_field(pc, IB_PC_ERR_RCVCONSTR_F, &val); 198 aggregate_8bit(&perf_count.rcvconstrainterrors, val); 199 mad_decode_field(pc, IB_PC_ERR_LOCALINTEG_F, &val); 200 aggregate_4bit(&perf_count.linkintegrityerrors, val); 201 mad_decode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &val); 202 aggregate_4bit(&perf_count.excbufoverrunerrors, val); 203 mad_decode_field(pc, IB_PC_VL15_DROPPED_F, &val); 204 aggregate_16bit(&perf_count.vl15dropped, val); 205 mad_decode_field(pc, IB_PC_XMT_BYTES_F, &val); 206 aggregate_32bit(&perf_count.xmtdata, val); 207 mad_decode_field(pc, IB_PC_RCV_BYTES_F, &val); 208 aggregate_32bit(&perf_count.rcvdata, val); 209 mad_decode_field(pc, IB_PC_XMT_PKTS_F, &val); 210 aggregate_32bit(&perf_count.xmtpkts, val); 211 mad_decode_field(pc, IB_PC_RCV_PKTS_F, &val); 212 aggregate_32bit(&perf_count.rcvpkts, val); 213} 214 215static void output_aggregate_perfcounters(ib_portid_t *portid) 216{ 217 char buf[1024]; 218 uint32_t val = ALL_PORTS; 219 220 /* set port_select to 255 to emulate AllPortSelect */ 221 mad_encode_field(pc, IB_PC_PORT_SELECT_F, &val); 222 mad_encode_field(pc, IB_PC_COUNTER_SELECT_F, &perf_count.counterselect); 223 mad_encode_field(pc, IB_PC_ERR_SYM_F, &perf_count.symbolerrors); 224 mad_encode_field(pc, IB_PC_LINK_RECOVERS_F, &perf_count.linkrecovers); 225 mad_encode_field(pc, IB_PC_LINK_DOWNED_F, &perf_count.linkdowned); 226 mad_encode_field(pc, IB_PC_ERR_RCV_F, &perf_count.rcverrors); 227 mad_encode_field(pc, IB_PC_ERR_PHYSRCV_F, &perf_count.rcvremotephyerrors); 228 mad_encode_field(pc, IB_PC_ERR_SWITCH_REL_F, &perf_count.rcvswrelayerrors); 229 mad_encode_field(pc, IB_PC_XMT_DISCARDS_F, &perf_count.xmtdiscards); 230 mad_encode_field(pc, IB_PC_ERR_XMTCONSTR_F, &perf_count.xmtconstrainterrors); 231 mad_encode_field(pc, IB_PC_ERR_RCVCONSTR_F, &perf_count.rcvconstrainterrors); 232 mad_encode_field(pc, IB_PC_ERR_LOCALINTEG_F, &perf_count.linkintegrityerrors); 233 mad_encode_field(pc, IB_PC_ERR_EXCESS_OVR_F, &perf_count.excbufoverrunerrors); 234 mad_encode_field(pc, IB_PC_VL15_DROPPED_F, &perf_count.vl15dropped); 235 mad_encode_field(pc, IB_PC_XMT_BYTES_F, &perf_count.xmtdata); 236 mad_encode_field(pc, IB_PC_RCV_BYTES_F, &perf_count.rcvdata); 237 mad_encode_field(pc, IB_PC_XMT_PKTS_F, &perf_count.xmtpkts); 238 mad_encode_field(pc, IB_PC_RCV_PKTS_F, &perf_count.rcvpkts); 239 240 mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc); 241 242 printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf); 243} 244 245static void aggregate_perfcounters_ext(void) 246{ 247 uint32_t val; 248 uint64_t val64; 249 250 mad_decode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val); 251 perf_count_ext.portselect = val; 252 mad_decode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &val); 253 perf_count_ext.counterselect = val; 254 mad_decode_field(pc, IB_PC_EXT_XMT_BYTES_F, &val64); 255 aggregate_64bit(&perf_count_ext.portxmitdata, val64); 256 mad_decode_field(pc, IB_PC_EXT_RCV_BYTES_F, &val64); 257 aggregate_64bit(&perf_count_ext.portrcvdata, val64); 258 mad_decode_field(pc, IB_PC_EXT_XMT_PKTS_F, &val64); 259 aggregate_64bit(&perf_count_ext.portxmitpkts, val64); 260 mad_decode_field(pc, IB_PC_EXT_RCV_PKTS_F, &val64); 261 aggregate_64bit(&perf_count_ext.portrcvpkts, val64); 262 mad_decode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &val64); 263 aggregate_64bit(&perf_count_ext.portunicastxmitpkts, val64); 264 mad_decode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &val64); 265 aggregate_64bit(&perf_count_ext.portunicastrcvpkts, val64); 266 mad_decode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &val64); 267 aggregate_64bit(&perf_count_ext.portmulticastxmitpkits, val64); 268 mad_decode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &val64); 269 aggregate_64bit(&perf_count_ext.portmulticastrcvpkts, val64); 270} 271 272static void output_aggregate_perfcounters_ext(ib_portid_t *portid) 273{ 274 char buf[1024]; 275 uint32_t val = ALL_PORTS; 276 277 /* set port_select to 255 to emulate AllPortSelect */ 278 mad_encode_field(pc, IB_PC_EXT_PORT_SELECT_F, &val); 279 mad_encode_field(pc, IB_PC_EXT_COUNTER_SELECT_F, &perf_count_ext.counterselect); 280 mad_encode_field(pc, IB_PC_EXT_XMT_BYTES_F, &perf_count_ext.portxmitdata); 281 mad_encode_field(pc, IB_PC_EXT_RCV_BYTES_F, &perf_count_ext.portrcvdata); 282 mad_encode_field(pc, IB_PC_EXT_XMT_PKTS_F, &perf_count_ext.portxmitpkts); 283 mad_encode_field(pc, IB_PC_EXT_RCV_PKTS_F, &perf_count_ext.portrcvpkts); 284 mad_encode_field(pc, IB_PC_EXT_XMT_UPKTS_F, &perf_count_ext.portunicastxmitpkts); 285 mad_encode_field(pc, IB_PC_EXT_RCV_UPKTS_F, &perf_count_ext.portunicastrcvpkts); 286 mad_encode_field(pc, IB_PC_EXT_XMT_MPKTS_F, &perf_count_ext.portmulticastxmitpkits); 287 mad_encode_field(pc, IB_PC_EXT_RCV_MPKTS_F, &perf_count_ext.portmulticastrcvpkts); 288 289 mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc); 290 291 printf("# Port counters: %s port %d\n%s", portid2str(portid), ALL_PORTS, buf); 292} 293 294static void dump_perfcounters(int extended, int timeout, uint16_t cap_mask, ib_portid_t *portid, 295 int port, int aggregate) 296{ 297 char buf[1024]; 298 299 if (extended != 1) { 300 if (!port_performance_query(pc, portid, port, timeout)) 301 IBERROR("perfquery"); 302 if (aggregate) 303 aggregate_perfcounters(); 304 else 305 mad_dump_perfcounters(buf, sizeof buf, pc, sizeof pc); 306 } else { 307 if (!(cap_mask & 0x200)) /* 1.2 errata: bit 9 is extended counter support */ 308 IBWARN("PerfMgt ClassPortInfo 0x%x extended counters not indicated\n", cap_mask); 309 310 if (!port_performance_ext_query(pc, portid, port, timeout)) 311 IBERROR("perfextquery"); 312 if (aggregate) 313 aggregate_perfcounters_ext(); 314 else 315 mad_dump_perfcounters_ext(buf, sizeof buf, pc, sizeof pc); 316 } 317 318 if (!aggregate) 319 printf("# Port counters: %s port %d\n%s", portid2str(portid), port, buf); 320} 321 322static void reset_counters(int extended, int timeout, int mask, ib_portid_t *portid, int port) 323{ 324 if (extended != 1) { 325 if (!port_performance_reset(pc, portid, port, mask, timeout)) 326 IBERROR("perf reset"); 327 } else { 328 if (!port_performance_ext_reset(pc, portid, port, mask, timeout)) 329 IBERROR("perf ext reset"); 330 } 331} 332 333int 334main(int argc, char **argv) 335{ 336 int mgmt_classes[4] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS}; 337 ib_portid_t *sm_id = 0, sm_portid = {0}; 338 ib_portid_t portid = {0}; 339 extern int ibdebug; 340 int dest_type = IB_DEST_LID; 341 int timeout = 0; /* use default */ 342 int mask = 0xffff, all_ports = 0; 343 int reset = 0, reset_only = 0; 344 int port = 0; 345 int udebug = 0; 346 char *ca = 0; 347 int ca_port = 0; 348 int extended = 0; 349 uint16_t cap_mask; 350 int all_ports_loop = 0; 351 int loop_ports = 0; 352 int node_type, num_ports = 0; 353 uint8_t data[IB_SMP_DATA_SIZE]; 354 int start_port = 1; 355 int enhancedport0; 356 int i; 357 358 static char const str_opts[] = "C:P:s:t:dGealrRVhu"; 359 static const struct option long_opts[] = { 360 { "C", 1, 0, 'C'}, 361 { "P", 1, 0, 'P'}, 362 { "debug", 0, 0, 'd'}, 363 { "Guid", 0, 0, 'G'}, 364 { "extended", 0, 0, 'e'}, 365 { "all_ports", 0, 0, 'a'}, 366 { "loop_ports", 0, 0, 'l'}, 367 { "reset_after_read", 0, 0, 'r'}, 368 { "Reset_only", 0, 0, 'R'}, 369 { "sm_portid", 1, 0, 's'}, 370 { "timeout", 1, 0, 't'}, 371 { "Version", 0, 0, 'V'}, 372 { "help", 0, 0, 'h'}, 373 { "usage", 0, 0, 'u'}, 374 { } 375 }; 376 377 argv0 = argv[0]; 378 379 while (1) { 380 int ch = getopt_long(argc, argv, str_opts, long_opts, NULL); 381 if ( ch == -1 ) 382 break; 383 switch(ch) { 384 case 'C': 385 ca = optarg; 386 break; 387 case 'P': 388 ca_port = strtoul(optarg, 0, 0); 389 break; 390 case 'e': 391 extended = 1; 392 break; 393 case 'a': 394 all_ports++; 395 port = ALL_PORTS; 396 break; 397 case 'l': 398 loop_ports++; 399 break; 400 case 'd': 401 ibdebug++; 402 madrpc_show_errors(1); 403 umad_debug(udebug); 404 udebug++; 405 break; 406 case 'G': 407 dest_type = IB_DEST_GUID; 408 break; 409 case 's': 410 if (ib_resolve_portid_str(&sm_portid, optarg, IB_DEST_LID, 0) < 0) 411 IBERROR("can't resolve SM destination port %s", optarg); 412 sm_id = &sm_portid; 413 break; 414 case 'r': 415 reset++; 416 break; 417 case 'R': 418 reset_only++; 419 break; 420 case 't': 421 timeout = strtoul(optarg, 0, 0); 422 madrpc_set_timeout(timeout); 423 break; 424 case 'V': 425 fprintf(stderr, "%s %s\n", argv0, get_build_version() ); 426 exit(-1); 427 default: 428 usage(); 429 break; 430 } 431 } 432 argc -= optind; 433 argv += optind; 434 435 if (argc > 1) 436 port = strtoul(argv[1], 0, 0); 437 if (argc > 2) 438 mask = strtoul(argv[2], 0, 0); 439 440 madrpc_init(ca, ca_port, mgmt_classes, 4); 441 442 if (argc) { 443 if (ib_resolve_portid_str(&portid, argv[0], dest_type, sm_id) < 0) 444 IBERROR("can't resolve destination port %s", argv[0]); 445 } else { 446 if (ib_resolve_self(&portid, &port, 0) < 0) 447 IBERROR("can't resolve self port %s", argv[0]); 448 } 449 450 /* PerfMgt ClassPortInfo is a required attribute */ 451 if (!perf_classportinfo_query(pc, &portid, port, timeout)) 452 IBERROR("classportinfo query"); 453 /* ClassPortInfo should be supported as part of libibmad */ 454 memcpy(&cap_mask, pc+2, sizeof(cap_mask)); /* CapabilityMask */ 455 cap_mask = ntohs(cap_mask); 456 if (!(cap_mask & 0x100)) { /* bit 8 is AllPortSelect */ 457 if (!all_ports && port == ALL_PORTS) 458 IBERROR("AllPortSelect not supported"); 459 if (all_ports) 460 all_ports_loop = 1; 461 } 462 463 if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { 464 if (smp_query(data, &portid, IB_ATTR_NODE_INFO, 0, 0) < 0) 465 IBERROR("smp query nodeinfo failed"); 466 node_type = mad_get_field(data, 0, IB_NODE_TYPE_F); 467 mad_decode_field(data, IB_NODE_NPORTS_F, &num_ports); 468 if (!num_ports) 469 IBERROR("smp query nodeinfo: num ports invalid"); 470 471 if (node_type == IB_NODE_SWITCH) { 472 if (smp_query(data, &portid, IB_ATTR_SWITCH_INFO, 0, 0) < 0) 473 IBERROR("smp query nodeinfo failed"); 474 enhancedport0 = mad_get_field(data, 0, IB_SW_ENHANCED_PORT0_F); 475 if (enhancedport0) 476 start_port = 0; 477 } 478 if (all_ports_loop && !loop_ports) 479 IBWARN("Emulating AllPortSelect by iterating through all ports"); 480 } 481 482 if (reset_only) 483 goto do_reset; 484 485 if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { 486 for (i = start_port; i <= num_ports; i++) 487 dump_perfcounters(extended, timeout, cap_mask, &portid, i, 488 (all_ports_loop && !loop_ports)); 489 if (all_ports_loop && !loop_ports) { 490 if (extended != 1) 491 output_aggregate_perfcounters(&portid); 492 else 493 output_aggregate_perfcounters_ext(&portid); 494 } 495 } 496 else 497 dump_perfcounters(extended, timeout, cap_mask, &portid, port, 0); 498 499 if (!reset) 500 exit(0); 501 502do_reset: 503 504 if (all_ports_loop || (loop_ports && (all_ports || port == ALL_PORTS))) { 505 for (i = start_port; i <= num_ports; i++) 506 reset_counters(extended, timeout, mask, &portid, i); 507 } 508 else 509 reset_counters(extended, timeout, mask, &portid, port); 510 511 exit(0); 512} 513