#!/bin/sh
#
# This file is released under the terms of the Artistic License.
# Please see the file LICENSE, included in this package, for details.
#
# Copyright The DBT-2 Authors
#

usage() {
	echo "usage: `basename $0` -h"
	echo "usage: `basename $0` -i <directory> [-o <directory>] [-b devices]"
	echo "options:"
	echo "       -b <comma delimited list of block devices (default: all devices)>"
	echo "       -i <DBT-2 test output directory>"
}

error() {
	echo "ERROR: $@"
	exit 1
}

warning() {
	echo "WARNING: $@"
}

create_stat_page()
{
	TITLE=$1
	TAG=$2
	DIR=$3
	ODIR=$4

	mkdir -p $ODIR

	cat > ${ODIR}/index.rst << __EOF__
================================================================================
Database Test 2 $TITLE $TAG Charts
================================================================================

$(show_images $DIR $TAG)
__EOF__
}

create_pidstat_page()
{
	TAG=$1
	DIR=$2

	mkdir -p $DIR

	PIDSTATINDEX="$(dirname "${PIDSTATCSV}")/pidstat-index.txt"

	cat > ${DIR}/index.rst << __EOF__
================================================================================
Database Test 2 pidstat $TAG Charts
================================================================================

$(show_images_pidstat "${TAG}" "${DIR}" "${PIDSTATINDEX}")
__EOF__
}

list_multiple_systems_summary()
{
	TITLE="$1"
	MYTAG="$2"

	echo "   * - **${TITLE}**"
	echo "     -"
	echo "     -"
	echo "     -"

	# The listing of system stastics is naively based on whether the uname.txt
	# was created by the get-os-info script.
	for UNAMEFILE in $(find ${INDIR}/$MYTAG -name uname.txt 2> /dev/null); do
		SNAME="$(basename $(dirname $UNAMEFILE))"
		echo "   * - $SNAME"
		echo "     - $(cat $UNAMEFILE)"
		echo "     - $(show_system_links ${MYTAG}/$SNAME)"
		echo "     - $(show_profile_links ${MYTAG}/${SNAME}/profile)"

		if [ -f "${INDIR}/${MYTAG}/${SNAME}/sysstat/sar.datafile" ]; then
			THISDIR="${INDIR}/${MYTAG}/$SNAME"
			create_stat_page $MYTAG cpu $THISDIR ${THISDIR}/cpu
			create_stat_page $MYTAG mem $THISDIR ${THISDIR}/mem
			create_stat_page $MYTAG blockdev $THISDIR ${THISDIR}/blockdev
			create_stat_page $MYTAG net $THISDIR ${THISDIR}/net
			create_stat_page $MYTAG paging $THISDIR ${THISDIR}/paging
			create_stat_page $MYTAG swap $THISDIR ${THISDIR}/swap
		fi
	done
}

list_processes()
{
	list_processes2 "Driver System(s):" driver
	list_processes2 "Client System(s):" client
	list_processes2 "Database System(s):" db
}

list_processes2()
{
	TITLE=$1
	MYPTAG=$2

	echo $TITLE
	echo ""
	PIDSTATFILES="$(find "${INDIR}/${MYPTAG}" -name pidstat.csv 2> /dev/null)"
	for PIDSTATCSV in ${PIDSTATFILES}; do
		ts plot-pidstat -i "${PIDSTATCSV}" \
				-o "$(dirname "${PIDSTATCSV}")/pidstat" &
	done
	wait

	for PIDSTATCSV in ${PIDSTATFILES}; do
		# Try not to count execution of the driver/client binaries on remote
		# systems.
		COUNTDRIVER=$(grep dbt2-driver "$PIDSTATCSV" | grep -c -v ssh)
		COUNTCLIENT=$(grep dbt2-client "$PIDSTATCSV" | grep -c -v ssh)
		SNAME=$(dirname "$(dirname "${PIDSTATCSV}")")
		SNAME=$(basename $SNAME)

		echo "* $SNAME"

		if [ $COUNTDRIVER -gt 0 ]; then
			PTAG="driver"
			create_pidstat_page $PTAG ${INDIR}/${MYPTAG}/${SNAME}/${PTAG}
			echo "   * \`$PTAG <${MYPTAG}/${SNAME}/${PTAG}/>\`__"
		fi
		if [ $COUNTCLIENT -gt 0 ]; then
			PTAG="client"
			create_pidstat_page $PTAG ${INDIR}/${MYPTAG}/${SNAME}/${PTAG}
			echo "   * \`$PTAG <${MYPTAG}/${SNAME}/${PTAG}/>\`__"
		fi
		echo ""
	done
}

show_images()
{
	DIR=$1
	TAG=$2

	CHARTS=$(find "${DIR}" -name "sar-${TAG}*.png" | sort -n)
	for CHART in $CHARTS; do
		FNAME=$(basename "${CHART}")
		echo ".. image:: ../sysstat/sar/${TAG}/${FNAME}"
		echo "   :target: ../sysstat/sar/${TAG}/${FNAME}"
		echo "   :width: 100%"
		echo ""
	done
}

show_images_pidstat()
{
	TAG=$1
	DIR=$2
	PINDEX=$3

	TAGPIDS=$(grep "dbt2-${TAG}" "${PINDEX}" | cut -d " " -f 1)
	for P in ${TAGPIDS}; do
		CHARTS=$(find "${DIR}/../sysstat/pidstat" \
				-name "pidstat-${P}-*.png" 2> /dev/null | sort)
		for CHART in ${CHARTS}; do
			BCHART=$(basename "${CHART}")
			echo ".. image:: ../sysstat/pidstat/${BCHART}"
			echo "   :target: ../sysstat/pidstat/${BCHART}"
			echo "   :width: 100%"
			echo ""
		done
	done
}

show_profile_links()
{
	PPATH=$1

	FILENAME="${INDIR}/${PPATH}/readprofile.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`readprofile <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/readprofile-load.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`readprofile-by-load <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/readprofile-ticks.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`readprofile-by-ticks <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/opreport.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`opreport <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/opreport-callgraph.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`opreport-callgraph <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/opannotate-assembly.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`opannotate-assembly <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/opannotate-source.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`opannotate-source <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/perf-report.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`perf-report <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/perf-trace.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`perf-trace <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/perf-annotate.txt"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`perf-annotated-source <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi

	FILENAME="${INDIR}/${PPATH}/flamegraph.svg"
	if [ -f "$FILENAME" ]; then
		printf "%s" "\`flame-graph <${PPATH}/$(basename "${FILENAME}")>\`__ "
	fi
}

show_system_links()
{
	SYSTEM=$1

	if [ -f "${INDIR}/${SYSTEM}/sysstat/sar.datafile" ]; then
		LINE="\`CPU <${SYSTEM}/cpu/>\`__"
		LINE="${LINE} \`Memory <${SYSTEM}/mem/>\`__"
		LINE="${LINE} \`Blockdev <${SYSTEM}/blockdev/>\`__"
		LINE="${LINE} \`Network <${SYSTEM}/net/>\`__"
		LINE="${LINE} \`Paging <${SYSTEM}/paging/>\`__"
		LINE="${LINE} \`Swap <${SYSTEM}/swap/>\`__"
		echo "${LINE}"
	else
		echo ".."
	fi
}

while getopts "hi:" opt; do
	case $opt in
	h)
		usage
		exit 1
		;;
	i)
		INDIR="$OPTARG"
		MIXLOG="${INDIR}/mix.log"
		OUTDIR="$INDIR"
		;;
	esac
done

SUMMARY="${INDIR}/summary.rst"
if [ ! -f "$SUMMARY" ]; then
	MIXFILE="${INDIR}/mix.log"
	dbt2 post-process "${MIXFILE}" > "${SUMMARY}"
	VERBOSE=1 dbt2 post-process "${MIXFILE}" > "${INDIR}/detailed-summary.rst"
fi

DBMS=`grep RDBMS $INDIR/readme.txt | cut -d " " -f 2`
if [ "x$DBMS" = "x" ]; then
	error "Could not determine what RDBMS used from results"
fi

DBNAME=`grep "Database Name" $INDIR/readme.txt | cut -d " " -f 3`
if [ "x$DBNAME" = "x" ]; then
	warning "Could not determine what the database name used from results"
fi

echo "Processing pidstat files..."
find "${INDIR}" -type f -name pidstat.txt 2> /dev/null | \
		while IFS= read -r PIDSTATFILE; do
	PDIR=$(dirname "${PIDSTATFILE}")
	ts process-pidstat -i "${PIDSTATFILE}"
done

echo "Generating transaction distribution charts..."
mkdir -p ${OUTDIR}/txn || exit 1
MIXFILES="$(find "${INDIR}/driver" -type f -name 'mix*.log' -print0 \
		2> /dev/null | xargs -0)"
# shellcheck disable=SC2086
(dbt-plot transaction-distribution Delivery d "${OUTDIR}/txn" 1 ${MIXFILES} \
		|| warning \
		"Could not create Delivery response time distribution char") &
# shellcheck disable=SC2086
(dbt-plot transaction-distribution "New Order" n "${OUTDIR}/txn" 2 \
		${MIXFILES} || warning \
		"Could not create New Order response time distribution char") &
# shellcheck disable=SC2086
(dbt-plot transaction-distribution "Order Status" o "${OUTDIR}/txn" 3 \
		${MIXFILES} || warning \
		"Could not create Order Status response time distribution char") &
# shellcheck disable=SC2086
(dbt-plot transaction-distribution "Payments" p "${OUTDIR}/txn" 4 ${MIXFILES} \
		|| warning \
		"Could not create Payments response time distribution char") &
# shellcheck disable=SC2086
(dbt-plot transaction-distribution "Stock Level" s "${OUTDIR}/txn" 5 \
		${MIXFILES} || warning \
		"Could not create Stock Level response time distribution char") &
wait

echo "Generating sar charts..."
# shellcheck disable=SC2044
for SARDIR in $(find "${INDIR}" -type d -name sysstat 2> /dev/null); do
	ts plot-sar -i "${SARDIR}/sar" &
done
wait

echo "Generating transaction rate charts..."
# shellcheck disable=SC2086
(dbt-plot transaction-rate "Delivery" d tpm "${OUTDIR}/txn" 1 ${MIXFILES} \
		|| warning "Could not create delivery transaction rate charts") &
# shellcheck disable=SC2086
(dbt-plot transaction-rate "New Order" n tpm "${OUTDIR}/txn" 2 ${MIXFILES} \
		|| warning "Could not create new order transaction rate charts") &
# shellcheck disable=SC2086
(dbt-plot transaction-rate "Order Status" o tpm "${OUTDIR}/txn" 3 ${MIXFILES} \
		|| warning "Could not create order status transaction rate charts") &
# shellcheck disable=SC2086
(dbt-plot transaction-rate "Payment" p tpm "${OUTDIR}/txn" 4 ${MIXFILES} \
		|| warning "Could not create payment transaction rate charts") &
# shellcheck disable=SC2086
(dbt-plot transaction-rate "Stock Level" s tpm "${OUTDIR}/txn" 5 ${MIXFILES} \
		|| warning "Could not create stock level transaction rate charts") &
wait

DBMSFILE="$(find "${INDIR}" -name "readme-${DBMS}.txt")"
if [ "${DBMSFILE}" = "" ]; then
	DBMSNAME=""
else
	DBMSNAME="$(head -n 1 "${DBMSFILE}")"
fi

REPORTFILE="${OUTDIR}/report.rst"
cat > $REPORTFILE << __EOF__
======================
Database Test 2 Report
======================

**These results are not comparable to TPC Benchmark(TM) C Results.**

Summary
=======

* Date: $(head -n 1 "${INDIR}/readme.txt")
* Scale Factor: $(grep "Database Scale Factor:" "${INDIR}/readme.txt" | cut -d ":" -f 2 | xargs)
* DBMS: ${DBMSNAME}

$(cat $SUMMARY)

Notes: $(head -n 2 ${INDIR}/readme.txt | tail -n 1)

Transaction Charts
==================

+------------+---------------------------------------+-----------------------------------+
|Transaction |            Response Time              |        Time Distribution          |
+============+=======================================+===================================+
|Delivery    |.. image:: txn/td-transaction-rate.png |.. image:: txn/td-distribution.png |
|            |   :target: txn/td-transaction-rate.png|   :target: txn/td-distribution.png|
|            |   :width: 100%                        |   :width: 100%                    |
+------------+---------------------------------------+-----------------------------------+
|New Order   |.. image:: txn/tn-transaction-rate.png |.. image:: txn/tn-distribution.png |
|            |   :target: txn/tn-transaction-rate.png|   :target: txn/tn-distribution.png|
|            |   :width: 100%                        |   :width: 100%                    |
+------------+---------------------------------------+-----------------------------------+
|Order Status|.. image:: txn/to-transaction-rate.png |.. image:: txn/to-distribution.png |
|            |   :target: txn/to-transaction-rate.png|   :target: txn/to-distribution.png|
|            |   :width: 100%                        |   :width: 100%                    |
+------------+---------------------------------------+-----------------------------------+
|Payment     |.. image:: txn/tp-transaction-rate.png |.. image:: txn/tp-distribution.png |
|            |   :target: txn/tp-transaction-rate.png|   :target: txn/tp-distribution.png|
|            |   :width: 100%                        |   :width: 100%                    |
+------------+---------------------------------------+-----------------------------------+
|Stock Level |.. image:: txn/ts-transaction-rate.png |.. image:: txn/ts-distribution.png |
|            |   :target: txn/ts-transaction-rate.png|   :target: txn/ts-distribution.png|
|            |   :width: 100%                        |   :width: 100%                    |
+------------+---------------------------------------+-----------------------------------+

System Summary
==============

.. list-table::
   :header-rows: 1

   * -
     - Operating System
     - Charts
     - Profiling
$(list_multiple_systems_summary "Driver System(s)" driver)
$(list_multiple_systems_summary "Client System(s)" client)
$(list_multiple_systems_summary "Database System(s)" db)

Component Statistics per Process
--------------------------------

$(list_processes)

$(dbt2 "${DBMS}-report" -i "${INDIR}" 2> /dev/null)
__EOF__

# Generate HTML and PDF files.
# TODO: An RST report is always generated, but automatically create HTML and
# PDF reports if we detect docutils and pandoc.  This should be a little
# smarter such that we should actually do some combination of generating
# formats requested or throw codes depending on what actually failed.

GENERATE_PDF=0

RST2HTML5=""
which rst2html5.py > /dev/null 2>&1
if [ $? -eq 0 ]; then
	RST2HTML5="rst2html5.py"
fi
which rst2html5 > /dev/null 2>&1
if [ $? -eq 0 ]; then
	RST2HTML5="rst2html5"
fi

if [ ! "x${RST2HTML5}" = "x" ]; then
	# pandoc can't properly convert multi-cell table headings from rst but
	# Sphinx's rst2html can. Then pandoc can convert multi-cell table headings
	# from html to pdf.

	find "${OUTDIR}" -name "*.rst" 2> /dev/null | while IFS= read -r RST; do
		RSTDIR=$(dirname "$RST")
		RSTNAME=$(basename "$RST")
		NAME="${RSTNAME%.*}"
		"$RST2HTML5" "$RST" "${RSTDIR}/${NAME}.html" 2> /dev/null
	done

	echo "Generated top level HTML reports:"
	find "${OUTDIR}" -maxdepth 1 -name '*.html' 2> /dev/null
	echo ""

    if [ $GENERATE_PDF -eq 1 ]; then
		# A pdf could be produced other ways, but I believe pandoc produces the
		# most minimally styled LaTeX looking document, as opposed to using
		# rst2latex, with default settings.
		if ! which pandoc > /dev/null 2>&1; then
			(cd "${OUTDIR}" && \
					pandoc -s report.html -f html -t pdf -o report.pdf \
							2> /dev/null)
			find "${OUTDIR}" -name "*.html" 2> /dev/null | \
					while IFS= read -r HTML; do
				HTMLDIR=$(dirname "$HTML")
				HTMLNAME=$(basename "$HTML")
				NAME="${HTMLNAME%.*}"
				pandoc -s "$HTML" -f html -t pdf \
						-o "${HTMLDIR}/${NAME}.pdf" 2> /dev/null
			done

			echo "Generated top level PDF reports:"
			find "${OUTDIR}" -maxdepth 1 -name '*.pdf' 2> /dev/null
			echo ""
		else
			echo "WARNING: pandoc required to generate pdf report"
			exit 0
		fi
	fi
else
	echo "WARNING: rst2html5 required to generate html report"
	exit 0
fi
