#!/bin/sh
#
# Script for saving endurance measurements.
# This file is part of sp-endurance.
#
# Copyright (C) 2006-2010 by Nokia Corporation
#
# Contact: Eero Tamminen <eero.tamminen@nokia.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License 
# version 2 as published by the Free Software Foundation. 
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301 USA
#
# Changelog
# 2006-11-09:
# - compress syslog
# - save the measurement files in to separate directories
# - add /sbin/ifconfig and interrupts/slabinfo/vmstat/stat files from /proc
# 2006-11-14:
# - save DSME statistics
# 2006-12-05:
# - save component version
# 2007-03-01:
# - don't require sp_smaps_snapshot
# - use script name Lintian is happy with
# 2007-04-18:
# - don't call separate script, do all things here
# 2007-11-01:
# - Save what FDs processes have open
# - Ask proc2csv to ignore permission errors so that this
#   can be used also as normal user
# 2007-11-05:
# - Compress smaps.cap
# 2007-11-28:
# - Store smaps data from here if sp_smaps_snapshot is missing
# 2008-01-14:
# - Check for argument starting with '-' or containing spaces
# 2008-04-30:
# - Support for optional use-case step description
# 2009-04-21:
# - Execute faster by switching compressor from gzip to lzop. The problem is
#   that Busybox gzip only supports compression level -9, ie. best but slowest.
#   Endurance report now includes information about CPU usage, so we dont skew
#   those results so much anymore.
# 2009-10-15:
# - Save xmeminfo error messages
# 2009-11-12:
# - Better OSSO_VERSION and error handling, show only relevant errors to
#   user, update file version
# 2010-03-04:
# - Use ifconfig -a so that all present interfaces are always listed.
#   This way it's easier to track the amounts transferred through them
#   (Desktop Linux interfaces zero values when they go down, N900 don't)
# 2010-04-20:
# - If use-case step description isn't given, add information about
#   focused / topmost application

script="${0##*/}"
# incorrect number of arguments or first argument starts with "-"
if [ $# -lt 1 ] || [ $# -gt 2 ] || [ "${1#-}" != "$1" ]; then
	echo
	echo "usage: $script <use-case-name> [step description]"
	echo
	echo "example: $script file-ops 'load large file'"
	echo
	echo "This saves required endurance measurements to a directory with"
	echo "given use-case name and optional use-case step description."
	echo "Data from each new measurement is saved into a numerically "
	echo "named subdirectories (starting from 101), like this:"
	echo "<use-case-name>/"
	echo "+ 101/"
	echo " - bootreason   (why device last booted)"
	echo " - component_version (HW identification)"
	echo " - ifconfig     (output of /sbin/ifconfig)"
	echo " - dsme/        (DSME lifeguard statistics)"
	echo " - interrupts   (number of different HW interrupts)"
	echo " - open-fds     (list of files/sockets open by processes)"
	echo " - slabinfo     (information about kernel caches, see slabinfo(5))"
	echo " - smaps.cap.gz (compressed SMAPS memory usage data)"
	echo " - stat         (kernel/system statistics, see proc(5))"
	echo " - syslog.gz    (compressed syslog contents)"
	echo " - usage.csv    (/proc info + X resource & disk usage in CSV format)"
	echo " - xres.log     (XRes related error messages from xmeminfo)"
	echo " - step.txt     (current use-case step description)"
	echo "+ 102/"
	echo "+ 103/"
	echo "etc."
	echo
	exit 1
fi

# do some basic sanity checks
if [ -z $(which proc2csv) ]; then
	echo "$script: ERROR, 'proc2csv' tool is missing from PATH" 1>&2
	exit 1
fi
if [ -z $(which xmeminfo) ]; then
	echo "$script: ERROR, 'xmeminfo' tool is missing from PATH" 1>&2
	exit 1
fi
if [ -z $(which lzop) ]; then
	echo "$script: ERROR, 'lzop' tool is missing from PATH" 1>&2
	exit 1
fi
if [ "${1#* }" != "$1" ]; then
	echo "$script: ERROR, argument '$1' contains space(s)" 1>&2
	exit 1
fi
name=$1

# real dumb way to do find free index, but normally this should be
# run less than 100 times...
for i in $(seq 999); do
	idx="$((100+$i))"
	if [ \! -d "$name/$idx" ]; then
		break
	fi
done
path="$name/$idx"

# directory for storing the new statistics
echo "Saving to $path:"
mkdir -p $path

# optional use-case step description
if [ $# -gt 1 ]; then
	echo "- use-case step description"
	echo "$2" > $path/step.txt
else
	echo "- use-case step desription (focused/topmost window)"
	if [ -z $(which xprop) ]; then
		echo "$script: WARNING, 'xprop' tool is missing from PATH" 1>&2
	else
		# _NET_ACTIVE_WINDOW standard property tells focused window,
		# WM_CLASS tells the "name" of the application owning that.
		# _MB_CURRENT_APP_WINDOW is Maemo/Matchbox property for
		# topmost window (can be different from focused one)
		for prop in _MB_CURRENT_APP_WINDOW _NET_ACTIVE_WINDOW; do
			win=$(xprop -root $prop|cut -s -d'#' -f2)
			if [ -z $win ]; then
				continue
			fi
			app=$(xprop -id $win WM_CLASS|cut -s -d'"' -f2)
			if [ -z "$app" ]; then
				app=$(xprop -id $win WM_NAME|cut -s -d'"' -f2)
				if [ -z "$app" ]; then
					continue
				fi
			fi
		done
		echo "$app" > $path/step.txt
	fi
fi

# save memory statistics
echo "- SMAPS data"
if [ -z $(which sp_smaps_snapshot) ]; then
	for pid in /proc/[0-9]*; do
		echo "==> $pid/smaps <=="
		awk '{print "#"$1,$2}' < $pid/status
		cat $pid/smaps
	done | lzop -c > $path/smaps.cap.lzo
else
	sp_smaps_snapshot | lzop -c > $path/smaps.cap.lzo
fi

# save most of /proc
usage=$path/usage.csv
echo "- /proc/ data in CSV format"
echo -e "generator = syte-endurance-stats v0.5\n" > $usage
if [ \! -z "$OSSO_VERSION" ]; then
	echo "SW-version = $OSSO_VERSION" >> $usage
elif [ \! -z $(which osso-product-info) ]; then
	echo "SW-version = $(osso-product-info -q OSSO_VERSION)" >> $usage
else
	echo "SW-version = <unknown>" >> $usage
fi
echo "date = $(date +'%F %T')" >> $usage
# all relevant info from the /proc that is easy to parse
proc2csv -p >> $usage
if [ $? -ne 0 ]; then
	echo "$script: WARNING, proc2csv failed with exit code $??" 1>&2
fi
# info on the UI processes X resource usage
echo "- X resource usage"
echo >> $usage
xmeminfo >> $usage 2> $path/xres.log
if [ $? -ne 0 ]; then
	echo "$script: WARNING, xmeminfo failed with exit code $?, is DISPLAY set?" 1>&2
fi
# output disk usage
echo "- Disk usage"
echo >> $usage
df|sed 's/ \+/,/g' >> $usage

# save some less easily parsed /proc/ statistics, ignore errors
echo "- Open file descriptors"
ls -l /proc/[0-9]*/fd/ > $path/open-fds 2> /dev/null
echo "- Other proc files"
cp /proc/slabinfo /proc/interrupts /proc/stat /proc/component_version /proc/bootreason $path/ 2> /dev/null

# save network and DSME stats
echo "- /sbin/ifconfig"
/sbin/ifconfig -a > $path/ifconfig
echo "- DSME statistics"
cp -a /var/lib/dsme $path/
 
# and syslog...
echo "- Syslog(s)"
if [ -f /var/ftd-log/syslog ]; then
	# old FTD rotated syslogs?
	logs="/var/ftd-log/logs/syslog /var/ftd-log/syslog"
elif [ -f /var/log/syslog ]; then
	# new FTD rotated syslogs?
	if [ -f /var/log/logs/syslog ]; then
		logs="/var/log/logs/syslog /var/log/syslog"
	else
		# plain syslog
		if [ -f /var/log/syslog.old ]; then
			logs="/var/log/syslog.old /var/log/syslog"
		else
			logs="/var/log/syslog"
		fi
	fi
else
	# no syslog
	echo "Syslog file(s) missing!" 1>&2
	exit 0
fi
cat $logs | lzop -c > $path/syslog.lzo
