#!/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 (C) 2006      Open Source Development Labs, Inc.
#               2014      2ndQuadrant, Ltd.
#               2006-2022 Mark Wong
#

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()
{
	local TITLE=$1
	local TAG=$2
	local DIR=$3
	local 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

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

$(show_images_pidstat $TAG $DIR)
__EOF__
}

create_pidstat_plots()
{
	MYPIDSTATCSV=$1
	METRIC=$2
	COMMAND=$3
	MYTAG=$4

	dbt-plot-pidstat -i $MYPIDSTATCSV -m $METRIC -c "$COMMAND" -t $MYTAG \
			-o $(dirname $MYPIDSTATCSV)/${MYTAG}
}

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)"

		if [ -f "${INDIR}/${MYTAG}/${SNAME}/sar_raw.out" ]; 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 swap $THISDIR ${THISDIR}/swap
		fi
	done
}

list_processes()
{
	METRICS="X.CPU X.usr X.system X.wait VSZ RSS X.MEM kB_rd.s kB_wr.s iodelay "
	METRICS="$METRICS cswch.s nvcswch.s threads fd.nr"

	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 ""
	for PIDSTATCSV in $(cd ${INDIR}/${MYPTAG} 2> /dev/null && find . -name pidstat.csv); do
		COUNTDRIVER=$(cd ${INDIR}/${MYPTAG} && grep dbt2-driver $PIDSTATCSV | wc -l)
		COUNTCLIENT=$(cd ${INDIR}/${MYPTAG} && grep dbt2-client $PIDSTATCSV | wc -l)
		SNAME=$(dirname $PIDSTATCSV)
		SNAME=$(basename $SNAME)

		echo "* $SNAME"

		if [ $COUNTDRIVER -gt 0 ]; then
			PTAG="driver"
			for M in $METRICS; do
					create_pidstat_plots ${INDIR}/${MYPTAG}/$PIDSTATCSV $M \
							dbt2-driver $PTAG
			done
			create_pidstat_page $PTAG ${INDIR}/${MYPTAG}/${SNAME}/${PTAG}
			echo "   * \`$PTAG <${MYPTAG}/${SNAME}/${PTAG}/>\`_"
		fi
		if [ $COUNTCLIENT -gt 0 ]; then
			PTAG="client"
			for M in $METRICS; do
					create_pidstat_plots ${INDIR}/${MYPTAG}/$PIDSTATCSV $M \
							dbt2-client $PTAG
			done
			create_pidstat_page $PTAG ${INDIR}/${MYPTAG}/${SNAME}/${PTAG}
			echo "   * \`$PTAG <${MYPTAG}/${SNAME}/${PTAG}/>\`_"
		fi
		echo ""
	done
}

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

	CHARTS=`(cd $DIR && find */ -name "sar-$TAG*.png")`
	for CHART in $CHARTS; do
		echo ".. image:: ../$CHART"
		echo "   :target: ../$CHART"
		echo "   :width: 100%"
		echo ""
	done
}

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

	CHARTS=$(cd $DIR && ls -1v pidstat-${TAG}-*.png)
	for CHART in $CHARTS; do
		echo ".. image:: $CHART"
		echo "   :target: $CHART"
		echo "   :width: 100%"
		echo ""
	done
}

show_profile_links()
{
	SYSTEM=$1

	FILENAME="${INDIR}/${SYSTEM}/readprofile.txt"
	if [ -f "$FILENAME" ]; then
		echo -n "\`readprofile <${SYSTEM}/$(basename $FILENAME)>\`__ "
	fi

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

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

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

	FILENAME="${INDIR}/${SYSTEM}/perf.txt"
	if [ -f "$FILENAME" ]; then
		which stackcollapse-perf.pl > /dev/null 2>&1
		if [ $? -eq 0 ]; then
			(cd $(dirname $FILENAME) && \
					stackcollapse-perf.pl perf.txt > perf.folded 2> /dev/null)
		fi
		which flamegraph.pl > /dev/null 2>&1
		if [ $? -eq 0 ]; then
			FLAMEGRAPH="${INDIR}/${SYSTEM}/flamegraph.svg"
			(cd $(dirname $FILENAME) && \
				flamegraph.pl perf.folded > $FLAMEGRAPH 2> /dev/null)
		fi
		if [ -f "$FLAMEGRAPH" ]; then
			echo -n "\`flame-graph <${SYSTEM}/$(basename ${FLAMEGRAPH})>\`__ "
		fi
	fi
}

show_system_links()
{
	SYSTEM=$1

	if [ -f "${INDIR}/${SYSTEM}/sar_raw.out" ]; then
		echo -n "\`CPU <${SYSTEM}/cpu/>\`__ "
		echo -n "\`Memory <${SYSTEM}/mem/>\`__ "
		echo -n "\`Blockdev <${SYSTEM}/blockdev/>\`__ "
		echo -n "\`Network <${SYSTEM}/net/>\`__ "
		echo -n "\`Swap <${SYSTEM}/swap/>\`__ "
	else
		echo ".."
	fi
}

while getopts "b:hi:" opt; do
	case $opt in
	b)
		BLKDEVICES=${OPTARG}
		;;
	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..."
for PIDSTATFILE in $(find $INDIR -name pidstat.txt); do
	DIRNAME="$(dirname $PIDSTATFILE)"
	(cd $DIRNAME && dbt-process-pidstat $PIDSTATFILE) &
done

echo "Generating transaction distribution charts..."
mkdir -p ${OUTDIR}/txn || exit 1
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-distribution Delivery d ${OUTDIR}/txn 1 \
		|| warning "Could not create Delivery response time distribution char" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-distribution "New Order" n ${OUTDIR}/txn 2 \
		|| warning "Could not create New Order response time distribution char" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-distribution "Order Status" o ${OUTDIR}/txn 3 \
		|| warning "Could not create Order Status response time distribution char" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-distribution "Payments" p ${OUTDIR}/txn 4 \
		|| warning "Could not create Payments response time distribution char" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-distribution "Stock Level" s ${OUTDIR}/txn 5 \
		|| warning "Could not create Stock Level response time distribution char" &

mkdir -p ${OUTDIR}/db/sar || exit 1

echo "Generating sar io charts..."
for SARBLOCKDEVFILE in `find $INDIR -name sar-blockdev.csv`; do
	DIRNAME="$(dirname $SARBLOCKDEVFILE)/sar"
	mkdir -p $DIRNAME
	dbt-plot-sar-blockdev $SARBLOCKDEVFILE $DIRNAME $BLKDEVICES \
			> /dev/null 2>&1 || warning "Could not create sar blockdev charts" &
done

echo "Generating memory charts..."
for SARMEMFILE in `find $INDIR -name sar-mem.csv`; do
	DIRNAME="$(dirname $SARMEMFILE)/sar"
	mkdir -p $DIRNAME
	dbt-plot-sar-mem -i $SARMEMFILE -o $DIRNAME > /dev/null 2>&1 \
			|| warning "Could not create sar mem charts from $SARMEMFILE" &
done

echo "Generating processor utilization charts..."
for SARCPUFILE in `find $INDIR -name sar-cpu.csv`; do
	DIRNAME="$(dirname $SARCPUFILE)/sar"
	mkdir -p $DIRNAME
	dbt-plot-sar-cpu $SARCPUFILE $DIRNAME > /dev/null 2>&1 \
			|| warning "Could not create sar cpu charts from $SARCPUFILE" &
done

echo "Generating swap charts..."
for SARSWAPFILE in `find $INDIR -name sar-swap.csv`; do
	DIRNAME="$(dirname $SARSWAPFILE)/sar"
	mkdir -p $DIRNAME
	dbt-plot-sar-swap $SARSWAPFILE $DIRNAME > /dev/null 2>&1 \
			|| warning "Could not create sar swap charts from $SARSWAPFILE" &
done

echo "Generating network charts..."
for SARNETFILE in `find $INDIR -name sar-net.csv`; do
	DIRNAME="$(dirname $SARNETFILE)/sar"
	mkdir -p $DIRNAME
	dbt-plot-sar-net $SARNETFILE $DIRNAME > /dev/null 2>&1 \
			|| warning "Could not create sar net charts from $SARNETFILE" &
done

echo "Generating transaction rate charts..."
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-rate "District" d tpm ${OUTDIR}/txn 1 \
		|| warning "Could not create district transaction rate charts" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-rate "New Order" n tpm ${OUTDIR}/txn 2 \
		|| warning "Could not create new order transaction rate charts" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-rate "Order Status" o tpm ${OUTDIR}/txn 3 \
		|| warning "Could not create order status transaction rate charts" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-rate "Payment" p tpm ${OUTDIR}/txn 4 \
		|| warning "Could not create payment transaction rate charts" &
find ${INDIR}/driver -name 'mix*.log' | \
		xargs dbt-plot-transaction-rate "Stock Level" s tpm ${OUTDIR}/txn 5 \
		|| warning "Could not create stock level transaction rate charts" &

wait

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

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

Summary
=======

$(head -n 1 ${INDIR}/readme.txt)

$(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.

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.

	for RST in $(find $OUTDIR -name "*.rst"); do
		NAME="${RST%.*}"
		(cd $(dirname $RST) && \
				$RST2HTML5 $(basename $RST) ${NAME}.html 2> /dev/null) &
	done
	wait

	echo "Generated top level HTML reports:"
	ls -1v ${OUTDIR}/*.html
	echo ""

	# 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.
	which pandoc > /dev/null 2>&1
	if [ $? -eq 0 ]; then
		(cd $OUTDIR && \
				pandoc -s report.html -f html -t pdf -o report.pdf \
						2> /dev/null)
		for HTML in $(find $OUTDIR -name "*.html"); do
			NAME="${HTML%.*}"
			(cd $(dirname $HTML) && \
					pandoc -s $(basename $HTML) -f html -t pdf -o ${NAME}.pdf \
							2> /dev/null) &
		done
		wait

		echo "Generated top level PDF reports:"
		ls -1v ${OUTDIR}/*.pdf
		echo ""
	else
		echo "pandoc required to generate pdf report"
		exit 1
	fi
else
	echo "rst2html5 required to generate html report"
	exit 1
fi
