xref: /spdk/scripts/perf/pm/collect-vmstat (revision 7025ceb9c119a6da0b6ee2013b6ae94b51fac2df)
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"
11
12help() {
13	cat <<- HELP
14
15		Usage: $0 [-h] [-c count] [-d dir] [-l] [-p prefix] [-r reprint_header_count]
16
17		-h - Print this message.
18		-c - Execute count times. 0 is the default and it means to run
19		     indefinitely.
20		-d - Directory where results should be saved. Default is /tmp.
21		-l - Save output of the script to a log file (dir/${0##*/}.pm.log).
22		-p - Add prefix to saved files.
23		-r - Stat count after which header should be re-printed. Default is 20.
24		-t - How long to wait before each stat dump. Default is 1s.
25
26		When started, ${0##*/} will enter loop to continuosly dump
27		vmstat. Each iteration will be logged to stderr and a log file
28		(dir/${0##*/}.pm.log).
29
30	HELP
31}
32
33get_extra_info() {
34	local match="" data
35
36	case "$PM_OS" in
37		Linux)
38			match+="|MemAvailable"
39			match+="|Shmem"
40			match+="|HugePages_(Total|Free)"
41			match+="|Hugepagesize"
42
43			data=($(grep -E "^($match):" /proc/meminfo | awk '{print $2}'))
44			;&
45		*) data+=("$TEST_TAG") ;;
46	esac
47	echo "${data[*]}"
48}
49
50set_extra_info_header() {
51	local -n header_ref=$1
52	local _header
53
54	# Keep the header ordered as in get_extra_info()
55	case "$PM_OS" in
56		Linux) _header="avail shmem hp_total hp_free hp_size test" ;;
57		FreeBSD) _header="test" ;;
58	esac
59
60	header_ref[0]="${header_ref[0]} ----extra info----"
61	header_ref[1]="${header_ref[1]} $_header"
62}
63
64_vmstat() {
65	local count=$1 interval=$2 reprint_header=${3:-20} _count
66	local vmstat vmstat_cmdline=() _vmstat stat_idx header=()
67
68	[[ $PM_OS == Linux ]] && vmstat_cmdline+=(--timestamp)
69
70	_count=$count
71	while ((stat_idx = stat_idx == reprint_header ? 1 : ++stat_idx, count <= 0 ? 1 : _count--)); do
72		mapfile -t vmstat < <(vmstat "${vmstat_cmdline[@]}")
73		# Enhance output to include stuff we are most interested in
74		vmstat[2]="${vmstat[2]} $(get_extra_info)"
75		if ((stat_idx == 1)); then
76			header=("${vmstat[@]::2}")
77			set_extra_info_header header
78			_vmstat=("${header[@]}" "${vmstat[2]}")
79		else
80			_vmstat=("${vmstat[2]}")
81		fi
82		printf '%s\n' "${_vmstat[@]}"
83		sleep "${interval}"
84	done
85}
86
87cleanup() {
88	rm_pm_pid
89}
90
91count=0
92interval=1
93log_to_file=no
94prefix=""
95reprint_header=20
96
97while getopts c:d:hlp:r:t: opt; do
98	case "$opt" in
99		c) count=$OPTARG ;;
100		d) PM_OUTPUTDIR=$OPTARG ;;
101		h)
102			help
103			exit 0
104			;;
105		l) log_to_file=yes ;;
106		p) prefix=$OPTARG ;;
107		r) reprint_header=$OPTARG ;;
108		t) interval=$OPTARG ;;
109		*) ;;
110	esac
111done
112
113declare -r log_file=${prefix:+${prefix}_}${0##*/}.pm.log
114
115mkdir -p "$PM_OUTPUTDIR"
116if [[ $log_to_file == yes ]]; then
117	printf 'Redirecting to %s\n' "$PM_OUTPUTDIR/$log_file" >&2
118	exec > "$PM_OUTPUTDIR/$log_file" 2>&1
119fi
120
121save_pm_pid
122trap 'cleanup' EXIT
123trap 'retag' USR1
124
125_vmstat "$count" "$interval" "$reprint_header"
126