1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2023 Intel Corporation 4# All rights reserved. 5 6shopt -s nullglob extglob 7 8pmdir=$(readlink -f "$(dirname "$0")") 9rootdir=$(readlink -f "$pmdir/../../../") 10source "$pmdir/common" 11source "$rootdir/test/scheduler/common.sh" 12 13help() { 14 cat <<- HELP 15 16 Usage: $0 [-h] [-c count] [-d dir] [-l] [-p prefix] [-r reprint_header_count] 17 18 -h - Print this message. 19 -c - Execute count times. 0 is the default and it means to run 20 indefinitely. 21 -d - Directory where results should be saved. Default is /tmp. 22 -l - Save output of the script to a log file (dir/${0##*/}.pm.log). 23 -p - Add prefix to saved files. 24 -r - Stat count after which header should be re-printed. Default is 20. 25 -t - How long to wait before each stat dump. Default is 1s. 26 27 When started, ${0##*/} will enter loop to continuously dump 28 vmstat. Each iteration will be logged to stderr and a log file 29 (dir/${0##*/}.pm.log). 30 31 HELP 32} 33 34get_extra_info() { 35 local match="" data node hp hps 36 37 case "$PM_OS" in 38 Linux) 39 match+="|MemAvailable" 40 match+="|Shmem" 41 match+="|HugePages_(Total|Free)" 42 match+="|Hugepagesize" 43 44 data=($(grep -E "^($match):" /proc/meminfo | awk '{print $2}')) 45 if is_numa; then 46 for node in "${nodes[@]}"; do 47 for hp in "/sys/devices/system/node/node$node/hugepages/"*; do 48 hps=${hps:+$hps,}N$node-${hp#*hugepages-}_f=$(< "$hp/free_hugepages") 49 hps=${hps:+$hps,}N$node-${hp#*hugepages-}_t=$(< "$hp/nr_hugepages") 50 done 51 done 52 data+=("$hps") 53 fi 54 ;& 55 *) data+=("$TEST_TAG") ;; 56 esac 57 echo "${data[*]}" 58} 59 60set_extra_info_header() { 61 local -n header_ref=$1 62 local _header 63 64 # Keep the header ordered as in get_extra_info() 65 case "$PM_OS" in 66 Linux) 67 _header="avail shmem hp_total hp_free hp_size" 68 if is_numa; then 69 _header+=" hp_per_node" 70 fi 71 _header+=" test" 72 ;; 73 FreeBSD) _header="test" ;; 74 esac 75 76 header_ref[0]="${header_ref[0]} ----extra info----" 77 header_ref[1]="${header_ref[1]} $_header" 78} 79 80_vmstat() { 81 local count=$1 interval=$2 reprint_header=${3:-20} _count 82 local vmstat vmstat_cmdline=() _vmstat stat_idx header=() 83 84 [[ $PM_OS == Linux ]] && vmstat_cmdline+=(--timestamp) 85 86 _count=$count 87 while ((stat_idx = stat_idx == reprint_header ? 1 : ++stat_idx, count <= 0 ? 1 : _count--)); do 88 mapfile -t vmstat < <(vmstat "${vmstat_cmdline[@]}") 89 # Enhance output to include stuff we are most interested in 90 vmstat[2]="${vmstat[2]} $(get_extra_info)" 91 if ((stat_idx == 1)); then 92 header=("${vmstat[@]::2}") 93 set_extra_info_header header 94 _vmstat=("${header[@]}" "${vmstat[2]}") 95 else 96 _vmstat=("${vmstat[2]}") 97 fi 98 printf '%s\n' "${_vmstat[@]}" 99 sleep "${interval}" 100 done 101} 102 103cleanup() { 104 rm_pm_pid 105} 106 107count=0 108interval=1 109log_to_file=no 110prefix="" 111reprint_header=20 112 113while getopts c:d:hlp:r:t: opt; do 114 case "$opt" in 115 c) count=$OPTARG ;; 116 d) PM_OUTPUTDIR=$OPTARG ;; 117 h) 118 help 119 exit 0 120 ;; 121 l) log_to_file=yes ;; 122 p) prefix=$OPTARG ;; 123 r) reprint_header=$OPTARG ;; 124 t) interval=$OPTARG ;; 125 *) ;; 126 esac 127done 128 129declare -r log_file=${prefix:+${prefix}_}${0##*/}.pm.log 130 131mkdir -p "$PM_OUTPUTDIR" 132if [[ $log_to_file == yes ]]; then 133 printf 'Redirecting to %s\n' "$PM_OUTPUTDIR/$log_file" >&2 134 exec > "$PM_OUTPUTDIR/$log_file" 2>&1 135fi 136 137save_pm_pid 138trap 'cleanup' EXIT 139trap 'retag' USR1 140 141map_cpus 142 143_vmstat "$count" "$interval" "$reprint_header" 144