xref: /spdk/scripts/perf/pm/collect-vmstat (revision 3fa77bf24625a476f3376bb780a23bf6a6d76a1e)
155013c9eSMichal Berger#!/usr/bin/env bash
255013c9eSMichal Berger#  SPDX-License-Identifier: BSD-3-Clause
355013c9eSMichal Berger#  Copyright (C) 2023 Intel Corporation
455013c9eSMichal Berger#  All rights reserved.
555013c9eSMichal Berger
655013c9eSMichal Bergershopt -s nullglob extglob
755013c9eSMichal Berger
855013c9eSMichal Bergerpmdir=$(readlink -f "$(dirname "$0")")
955013c9eSMichal Bergerrootdir=$(readlink -f "$pmdir/../../../")
108d588fbcSMichal Bergersource "$pmdir/common"
11*3fa77bf2SMichal Bergersource "$rootdir/test/scheduler/common.sh"
1255013c9eSMichal Berger
1355013c9eSMichal Bergerhelp() {
1455013c9eSMichal Berger	cat <<- HELP
1555013c9eSMichal Berger
16d5fe62b2SMichal Berger		Usage: $0 [-h] [-c count] [-d dir] [-l] [-p prefix] [-r reprint_header_count]
1755013c9eSMichal Berger
1855013c9eSMichal Berger		-h - Print this message.
1955013c9eSMichal Berger		-c - Execute count times. 0 is the default and it means to run
2055013c9eSMichal Berger		     indefinitely.
2155013c9eSMichal Berger		-d - Directory where results should be saved. Default is /tmp.
22d5fe62b2SMichal Berger		-l - Save output of the script to a log file (dir/${0##*/}.pm.log).
2355013c9eSMichal Berger		-p - Add prefix to saved files.
2455013c9eSMichal Berger		-r - Stat count after which header should be re-printed. Default is 20.
2555013c9eSMichal Berger		-t - How long to wait before each stat dump. Default is 1s.
2655013c9eSMichal Berger
2734edd9f1SKamil Godzwon		When started, ${0##*/} will enter loop to continuously dump
2855013c9eSMichal Berger		vmstat. Each iteration will be logged to stderr and a log file
2955013c9eSMichal Berger		(dir/${0##*/}.pm.log).
3055013c9eSMichal Berger
3155013c9eSMichal Berger	HELP
3255013c9eSMichal Berger}
3355013c9eSMichal Berger
3406243cb0SMichal Bergerget_extra_info() {
35*3fa77bf2SMichal Berger	local match="" data node hp hps
3655013c9eSMichal Berger
3706243cb0SMichal Berger	case "$PM_OS" in
3806243cb0SMichal Berger		Linux)
3955013c9eSMichal Berger			match+="|MemAvailable"
4055013c9eSMichal Berger			match+="|Shmem"
4155013c9eSMichal Berger			match+="|HugePages_(Total|Free)"
4255013c9eSMichal Berger			match+="|Hugepagesize"
4355013c9eSMichal Berger
4455013c9eSMichal Berger			data=($(grep -E "^($match):" /proc/meminfo | awk '{print $2}'))
45*3fa77bf2SMichal Berger			if is_numa; then
46*3fa77bf2SMichal Berger				for node in "${nodes[@]}"; do
47*3fa77bf2SMichal Berger					for hp in "/sys/devices/system/node/node$node/hugepages/"*; do
48*3fa77bf2SMichal Berger						hps=${hps:+$hps,}N$node-${hp#*hugepages-}_f=$(< "$hp/free_hugepages")
49*3fa77bf2SMichal Berger						hps=${hps:+$hps,}N$node-${hp#*hugepages-}_t=$(< "$hp/nr_hugepages")
50*3fa77bf2SMichal Berger					done
51*3fa77bf2SMichal Berger				done
52*3fa77bf2SMichal Berger				data+=("$hps")
53*3fa77bf2SMichal Berger			fi
5406243cb0SMichal Berger			;&
5506243cb0SMichal Berger		*) data+=("$TEST_TAG") ;;
5606243cb0SMichal Berger	esac
5755013c9eSMichal Berger	echo "${data[*]}"
5855013c9eSMichal Berger}
5955013c9eSMichal Berger
6006243cb0SMichal Bergerset_extra_info_header() {
6106243cb0SMichal Berger	local -n header_ref=$1
6206243cb0SMichal Berger	local _header
6306243cb0SMichal Berger
6406243cb0SMichal Berger	# Keep the header ordered as in get_extra_info()
6506243cb0SMichal Berger	case "$PM_OS" in
66*3fa77bf2SMichal Berger		Linux)
67*3fa77bf2SMichal Berger			_header="avail shmem hp_total hp_free hp_size"
68*3fa77bf2SMichal Berger			if is_numa; then
69*3fa77bf2SMichal Berger				_header+=" hp_per_node"
70*3fa77bf2SMichal Berger			fi
71*3fa77bf2SMichal Berger			_header+=" test"
72*3fa77bf2SMichal Berger			;;
7306243cb0SMichal Berger		FreeBSD) _header="test" ;;
7406243cb0SMichal Berger	esac
7506243cb0SMichal Berger
7606243cb0SMichal Berger	header_ref[0]="${header_ref[0]} ----extra info----"
7706243cb0SMichal Berger	header_ref[1]="${header_ref[1]} $_header"
7806243cb0SMichal Berger}
7906243cb0SMichal Berger
8055013c9eSMichal Berger_vmstat() {
8155013c9eSMichal Berger	local count=$1 interval=$2 reprint_header=${3:-20} _count
8206243cb0SMichal Berger	local vmstat vmstat_cmdline=() _vmstat stat_idx header=()
8306243cb0SMichal Berger
8406243cb0SMichal Berger	[[ $PM_OS == Linux ]] && vmstat_cmdline+=(--timestamp)
8555013c9eSMichal Berger
8655013c9eSMichal Berger	_count=$count
8755013c9eSMichal Berger	while ((stat_idx = stat_idx == reprint_header ? 1 : ++stat_idx, count <= 0 ? 1 : _count--)); do
8806243cb0SMichal Berger		mapfile -t vmstat < <(vmstat "${vmstat_cmdline[@]}")
8955013c9eSMichal Berger		# Enhance output to include stuff we are most interested in
9006243cb0SMichal Berger		vmstat[2]="${vmstat[2]} $(get_extra_info)"
9155013c9eSMichal Berger		if ((stat_idx == 1)); then
9255013c9eSMichal Berger			header=("${vmstat[@]::2}")
9306243cb0SMichal Berger			set_extra_info_header header
9455013c9eSMichal Berger			_vmstat=("${header[@]}" "${vmstat[2]}")
9555013c9eSMichal Berger		else
9655013c9eSMichal Berger			_vmstat=("${vmstat[2]}")
9755013c9eSMichal Berger		fi
9855013c9eSMichal Berger		printf '%s\n' "${_vmstat[@]}"
9906243cb0SMichal Berger		sleep "${interval}"
100d5fe62b2SMichal Berger	done
101d5fe62b2SMichal Berger}
102d5fe62b2SMichal Berger
103d5fe62b2SMichal Bergercleanup() {
104d5fe62b2SMichal Berger	rm_pm_pid
10555013c9eSMichal Berger}
10655013c9eSMichal Berger
10755013c9eSMichal Bergercount=0
10855013c9eSMichal Bergerinterval=1
109d5fe62b2SMichal Bergerlog_to_file=no
11055013c9eSMichal Bergerprefix=""
11155013c9eSMichal Bergerreprint_header=20
11255013c9eSMichal Berger
113d5fe62b2SMichal Bergerwhile getopts c:d:hlp:r:t: opt; do
11455013c9eSMichal Berger	case "$opt" in
11555013c9eSMichal Berger		c) count=$OPTARG ;;
116d5fe62b2SMichal Berger		d) PM_OUTPUTDIR=$OPTARG ;;
11755013c9eSMichal Berger		h)
11855013c9eSMichal Berger			help
11955013c9eSMichal Berger			exit 0
12055013c9eSMichal Berger			;;
121d5fe62b2SMichal Berger		l) log_to_file=yes ;;
12255013c9eSMichal Berger		p) prefix=$OPTARG ;;
12355013c9eSMichal Berger		r) reprint_header=$OPTARG ;;
12455013c9eSMichal Berger		t) interval=$OPTARG ;;
12555013c9eSMichal Berger		*) ;;
12655013c9eSMichal Berger	esac
12755013c9eSMichal Bergerdone
12855013c9eSMichal Berger
12955013c9eSMichal Bergerdeclare -r log_file=${prefix:+${prefix}_}${0##*/}.pm.log
13055013c9eSMichal Berger
131d5fe62b2SMichal Bergermkdir -p "$PM_OUTPUTDIR"
132d5fe62b2SMichal Bergerif [[ $log_to_file == yes ]]; then
133d5fe62b2SMichal Berger	printf 'Redirecting to %s\n' "$PM_OUTPUTDIR/$log_file" >&2
134d5fe62b2SMichal Berger	exec > "$PM_OUTPUTDIR/$log_file" 2>&1
135d5fe62b2SMichal Bergerfi
13655013c9eSMichal Berger
137d5fe62b2SMichal Bergersave_pm_pid
138d5fe62b2SMichal Bergertrap 'cleanup' EXIT
1398d588fbcSMichal Bergertrap 'retag' USR1
1408d588fbcSMichal Berger
141*3fa77bf2SMichal Bergermap_cpus
142*3fa77bf2SMichal Berger
14355013c9eSMichal Berger_vmstat "$count" "$interval" "$reprint_header"
144