1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
|
#!/bin/bash
# BEGIN_ICS_COPYRIGHT8 ****************************************
#
# Copyright (c) 2015-2020, Intel Corporation
#
# 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.
#
# END_ICS_COPYRIGHT8 ****************************************
# [ICS VERSION STRING: unknown]
# take output from two runs of opaextractperf2 and merge them by computing
# differences in performance counters
tempfile="$(mktemp)"
trap "rm -f ${tempfile}.prefix1 ${tempfile}.prefix2; exit 1" SIGHUP SIGTERM SIGINT
trap "rm -f ${tempfile}.prefix1 ${tempfile}.prefix2" EXIT
Usage_full()
{
echo "Usage: ${cmd} before.csv after.csv" >&2
echo " or" >&2
echo " ${cmd} --help" >&2
echo " --help - produce full help text." >&2
echo " before.csv - output from a opaextractperf2 run" >&2
echo " after.csv - output from a opaextractperf2 run" >&2
echo >&2
echo "${cmd} merges output from two opaextactperf2 runs from the same fabric" >&2
echo "Counters for matching links will be computed (before subtracted from after)" >&2
echo "and a CSV file equivalent to opaextractperf2's output format will be generated" >&2
echo "suitable for importing into a spreadsheet or parsing by other scripts." >&2
echo >&2
echo "The before.csv and after.csv input files must be generated from the same" >&2
echo "fabric, with before.csv containing counters prior to after.csv." >&2
echo "Both files must have been generated to contain the running counters without" >&2
echo "any counter clears between before.csv and after.csv and without using any" >&2
echo "interval options to opareport which might report delta counters as" >&2
echo "opposed to running counters, such as opareport -i" >&2
echo "or opareport with both --begin and --end options." >&2
echo >&2
echo "for example:" >&2
echo " ${cmd} before.csv after.csv > delta.csv" >&2
echo >&2
exit 0
}
Usage()
{
echo "Usage: ${cmd} before.csv after.csv" >&2
echo " or" >&2
echo " ${cmd} --help" >&2
echo " --help - produce full help text." >&2
echo " before.csv - output from a opaextractperf2 run" >&2
echo " after.csv - output from a opaextractperf2 run" >&2
echo >&2
echo "for example:" >&2
echo " ${cmd} before.csv after.csv > delta.csv" >&2
echo >&2
exit 2
}
## Main function
res=0
cmd=`basename $0`
if [ x"$1" = "x--help" ]
then
Usage_full
fi
if [ "$#" != 2 ]
then
Usage
fi
f1="$1"
f2="$2"
if [ ! -e "$f1" ]
then
echo "$f1: Not Found" >&2
Usage
fi
if [ ! -e "$f2" ]
then
echo "$f2: Not Found" >&2
Usage
fi
IFS=';'
# omit heading line
# add sequencing number and line number before desc;type;guid;port so same
# device in each file will sort next to eachother and f1 sorts before f2.
nl -s';' "$f1"|tail -n+2 | sed -e 's/^ */1;/'|sort --field-separator=';' --key='5,6' > ${tempfile}.prefix1
nl -s';' "$f2"|tail -n+2 | sed -e 's/^ */2;/'|sort --field-separator=';' --key='5,6' > ${tempfile}.prefix2
# some debug code which can help identify nodes which are not in both files
#cut -f3-6 -d';' ${tempfile}.prefix1 > ${tempfile}.nodes1
#cut -f3-6 -d';' ${tempfile}.prefix2 > ${tempfile}.nodes2
#if ! diff ${tempfile}.nodes1 ${tempfile}.nodes2 > /dev/null
#then
# echo "$cmd: Warning: node list mismatch" >&2
# #diff -c ${tempfile}.nodes1 ${tempfile}.nodes2 | head -20
#fi
IFS=';'
{
# output heading
head -1 "$f1"
# compute counter differences f2 - f1
use_2=n # do _2 variables potentially have 1st line ("1") for a port
# sort by guid;port then prefix, this puts same ports next to eachother with
# line from f1 before line from f2
# the loop must handle cases where a device appears only in f1 or f2
# as well as where the neighbor to a device has changed between f1 and f2
# in a stable fabric these will not happen. However in a fabric with a few
# bad links, devices offline or where cables have been moved, this can happen
( cat ${tempfile}.prefix1 ${tempfile}.prefix2|sort --field-separator=';' --key='5,6' --key '1,1'; echo "END" ) | \
while read num_1 lineno_1 NodeDesc_1 NodeType_1 NodeGUID_1 PortNum_1 nNodeDesc_1 nNodeType_1 nNodeGUID_1 nPortNum_1 LinkSpeedActive_1 LinkWidthDnGradeTxActive_1 LinkWidthDnGradeRxActive_1 XmitDataMB_1 XmitData_1 XmitPkts_1 MulticastXmitPkts_1 RcvDataMB_1 RcvData_1 RcvPkts_1 MulticastRcvPkts_1 XmitWait_1 CongDiscards_1 XmitTimeCong_1 MarkFECN_1 RcvFECN_1 RcvBECN_1 RcvBubble_1 XmitWastedBW_1 XmitWaitData_1 LinkQualityIndicator_1 LocalLinkIntegrityErrors_1 RcvErrors_1 ExcessiveBufferOverruns_1 LinkErrorRecovery_1 LinkDowned_1 UncorrectableErrors_1 FMConfigErrors_1 XmitConstraintErrors_1 RcvConstraintErrors_1 RcvSwitchRelayErrors_1 XmitDiscards_1 RcvRemotePhysicalErrors_1
do
if [ x"$num_1" = x"END" ]
then
# normal end of file
break
fi
if ! [[ x"$RcvRemotePhysicalErrors_1" =~ ^x[0-9]+$ ]]
then
# lines with insufficient columns, extra columns or non-numeric in
# last column will fail the test. To balance performance and input
# checking we only check the last column since invalid input files
# will typically have the wrong number of columns
if [ x"$num_1" = x"1" ]
then
echo "$cmd: Invalid input line: $lineno_1 file: $f1" >&2
else
echo "$cmd: Invalid input line: $lineno_1 file: $f2" >&2
fi
exit 1
fi
if [ x"$num_1" = x"2" ]
then
#echo "process num_1=2" >&2
if [ "$use_2" != y ]
then
# "2" without a preceeding "1", skip line just read into _1
echo "$cmd: Warning: skipping unmatched line $lineno_1 in after: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1" >&2
else
# _2 has our "1", _1 has our "2"
if [ x"$NodeGUID_1" != x"$NodeGUID_2" -o x"$PortNum_1" != x"$PortNum_2" ]
then
# got a "1" followed by a "2" and they don't match, skip both
echo "$cmd: Warning: skipping unmatched line $lineno_2 in before: $NodeDesc_2;$NodeType_2;$NodeGUID_2;$PortNum_2" >&2
echo "$cmd: Warning: skipping unmatched line $lineno_1 in after: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1" >&2
elif [ x"$nNodeGUID_1" != x"$nNodeGUID_2" -o x"$nPortNum_1" != x"$nPortNum_2" ]
then
# we got a "1" followed by "2", however neighbor changed
echo "$cmd: Warning: skipping changed line $lineno_2 in before: $NodeDesc_2;$NodeType_2;$NodeGUID_2;$PortNum_2;$nNodeDesc_2;$nNodeType_2;$nNodeGUID_2;$nPortNum_2" >&2
echo "$cmd: Warning: skipping changed line $lineno_1 in after: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1;$nNodeDesc_1;$nNodeType_1;$nNodeGUID_1;$nPortNum_1" >&2
else
#echo "process num_1=2 use_2" >&2
# use _2 as before and _1 as after when compute delta
# for fields not subtracted, show after (_1) as more recent
echo "$NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1;$nNodeDesc_1;$nNodeType_1;$nNodeGUID_1;$nPortNum_1;$LinkSpeedActive_1;$LinkWidthDnGradeTxActive_1;$LinkWidthDnGradeRxActive_1;$(($XmitDataMB_1 - $XmitDataMB_2));$(($XmitData_1 - $XmitData_2));$(($XmitPkts_1 - $XmitPkts_2));$(($MulticastXmitPkts_1 - $MulticastXmitPkts_2));$(($RcvDataMB_1 - $RcvDataMB_2));$(($RcvData_1 - $RcvData_2));$(($RcvPkts_1 - $RcvPkts_2));$(($MulticastRcvPkts_1 - $MulticastRcvPkts_2));$(($XmitWait_1 - $XmitWait_2));$(($CongDiscards_1 - $CongDiscards_2));$(($XmitTimeCong_1 - $XmitTimeCong_2));$(($MarkFECN_1 - $MarkFECN_2));$(($RcvFECN_1 - $RcvFECN_2));$(($RcvBECN_1 - $RcvBECN_2));$(($RcvBubble_1 - $RcvBubble_2));$(($XmitWastedBW_1 - $XmitWastedBW_2));$(($XmitWaitData_1 - $XmitWaitData_2));$(($LinkQualityIndicator_1 < $LinkQualityIndicator_2?$LinkQualityIndicator_1:$LinkQualityIndicator_2));$(($LocalLinkIntegrityErrors_1 - $LocalLinkIntegrityErrors_2));$(($RcvErrors_1 - $RcvErrors_2));$(($ExcessiveBufferOverruns_1 - $ExcessiveBufferOverruns_2));$(($LinkErrorRecovery_1 - $LinkErrorRecovery_2));$(($LinkDowned_1 - $LinkDowned_2));$(($UncorrectableErrors_1 - $UncorrectableErrors_2));$(($FMConfigErrors_1 - $FMConfigErrors_2));$(($XmitConstraintErrors_1 - $XmitConstraintErrors_2));$(($RcvConstraintErrors_1 - $RcvConstraintErrors_2));$(($RcvSwitchRelayErrors_1 - $RcvSwitchRelayErrors_2));$(($XmitDiscards_1 - $XmitDiscards_2));$(($RcvRemotePhysicalErrors_1 - $RcvRemotePhysicalErrors_2))"
fi
fi
else
# num_1 is "1"
read num_2 lineno_2 NodeDesc_2 NodeType_2 NodeGUID_2 PortNum_2 nNodeDesc_2 nNodeType_2 nNodeGUID_2 nPortNum_2 LinkSpeedActive_2 LinkWidthDnGradeTxActive_2 LinkWidthDnGradeRxActive_2 XmitDataMB_2 XmitData_2 XmitPkts_2 MulticastXmitPkts_2 RcvDataMB_2 RcvData_2 RcvPkts_2 MulticastRcvPkts_2 XmitWait_2 CongDiscards_2 XmitTimeCong_2 MarkFECN_2 RcvFECN_2 RcvBECN_2 RcvBubble_2 XmitWastedBW_2 XmitWaitData_2 LinkQualityIndicator_2 LocalLinkIntegrityErrors_2 RcvErrors_2 ExcessiveBufferOverruns_2 LinkErrorRecovery_2 LinkDowned_2 UncorrectableErrors_2 FMConfigErrors_2 XmitConstraintErrors_2 RcvConstraintErrors_2 RcvSwitchRelayErrors_2 XmitDiscards_2 RcvRemotePhysicalErrors_2
#echo "process num_2=$num_2" >&2
if [ x"$num_2" = x"END" ]
then
# "1" without a "2" at end of file
echo "$cmd: Warning: skipping unmatched line $lineno_1 in before: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1" >&2
break
fi
if ! [[ x"$RcvRemotePhysicalErrors_2" =~ ^x[0-9]+$ ]]
then
# lines with insufficient columns, extra columns or non-numeric in
# last column will fail the test. To balance performance and input
# checking we only check the last column since invalid input files
# will typically have the wrong number of columns
if [ x"$num_2" = x"1" ]
then
echo "$cmd: Invalid input line: $lineno_2 file: $f1" >&2
else
echo "$cmd: Invalid input line: $lineno_2 file: $f2" >&2
fi
exit 1
fi
if [ x"$num_2" = x"1" ]
then
# two "1" in a row, skip _1, use this line for next pairing
echo "$cmd: Warning: skipping unmatched line $lineno_1 in before: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1" >&2
use_2=y
continue
elif [ x"$num_1" != "x1" -o x"$num_2" != "x2" ] # paranoid check
then
echo "$num_1 $num_2" >&2
echo "$cmd: Script Error: Incorrect sort order" >&2
exit 1
else
if [ x"$NodeGUID_1" != x"$NodeGUID_2" -o x"$PortNum_1" != x"$PortNum_2" ]
then
# "1" followed by non-matching "2", skip both
echo "$cmd: Warning: skipping unmatched line $lineno_1 in before: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1" >&2
echo "$cmd: Warning: skipping unmatched line $lineno_2 in after: $NodeDesc_2;$NodeType_2;$NodeGUID_2;$PortNum_2" >&2
elif [ x"$nNodeGUID_1" != x"$nNodeGUID_2" -o x"$nPortNum_1" != x"$nPortNum_2" ]
then
# we got a "1" followed by "2", however neighbor changed
echo "$cmd: Warning: skipping changed line $lineno_1 in before: $NodeDesc_1;$NodeType_1;$NodeGUID_1;$PortNum_1;$nNodeDesc_1;$nNodeType_1;$nNodeGUID_1;$nPortNum_1" >&2
echo "$cmd: Warning: skipping changed line $lineno_2 in after: $NodeDesc_2;$NodeType_2;$NodeGUID_2;$PortNum_2;$nNodeDesc_2;$nNodeType_2;$nNodeGUID_2;$nPortNum_2" >&2
else
# for fields not subtracted, show after (_2) as more recent
echo "$NodeDesc_2;$NodeType_2;$NodeGUID_2;$PortNum_2;$nNodeDesc_2;$nNodeType_2;$nNodeGUID_2;$nPortNum_2;$LinkSpeedActive_2;$LinkWidthDnGradeTxActive_2;$LinkWidthDnGradeRxActive_2;$(($XmitDataMB_2 - $XmitDataMB_1));$(($XmitData_2 - $XmitData_1));$(($XmitPkts_2 - $XmitPkts_1));$(($MulticastXmitPkts_2 - $MulticastXmitPkts_1));$(($RcvDataMB_2 - $RcvDataMB_1));$(($RcvData_2 - $RcvData_1));$(($RcvPkts_2 - $RcvPkts_1));$(($MulticastRcvPkts_2 - $MulticastRcvPkts_1));$(($XmitWait_2 - $XmitWait_1));$(($CongDiscards_2 - $CongDiscards_1));$(($XmitTimeCong_2 - $XmitTimeCong_1));$(($MarkFECN_2 - $MarkFECN_1));$(($RcvFECN_2 - $RcvFECN_1));$(($RcvBECN_2 - $RcvBECN_1));$(($RcvBubble_2 - $RcvBubble_1));$(($XmitWastedBW_2 - $XmitWastedBW_1));$(($XmitWaitData_2 - $XmitWaitData_1));$(($LinkQualityIndicator_2 < $LinkQualityIndicator_1?$LinkQualityIndicator_2:$LinkQualityIndicator_1));$(($LocalLinkIntegrityErrors_2 - $LocalLinkIntegrityErrors_1));$(($RcvErrors_2 - $RcvErrors_1));$(($ExcessiveBufferOverruns_2 - $ExcessiveBufferOverruns_1));$(($LinkErrorRecovery_2 - $LinkErrorRecovery_1));$(($LinkDowned_2 - $LinkDowned_1));$(($UncorrectableErrors_2 - $UncorrectableErrors_1));$(($FMConfigErrors_2 - $FMConfigErrors_1));$(($XmitConstraintErrors_2 - $XmitConstraintErrors_1));$(($RcvConstraintErrors_2 - $RcvConstraintErrors_1));$(($RcvSwitchRelayErrors_2 - $RcvSwitchRelayErrors_1));$(($XmitDiscards_2 - $XmitDiscards_1));$(($RcvRemotePhysicalErrors_2 - $RcvRemotePhysicalErrors_1))"
fi
fi
fi
use_2=n
done
}
res=$?
rm -rf ${tempfile}.prefix1 ${tempfile}.prefix2
exit $res
|