#!/bin/bash
set -u

function print_usage()
{
    cat << EOF
$(basename "$0") -- NVTX Push/Pop Range Summary

    No arguments.

    Output: All time values given in nanoseconds
        Time(%) : Percentage of "Total Time"
        Total Time : The total time used by all instances of this range
        Instances: The number of instances of this range
        Average : The average execution time of this range
        Minimum : The smallest execution time of this range
        Maximum : The largest execution time of this range
        Range : The name of the range

    This report provides a summary of NV Tools Extensions Push/Pop Ranges and
    their execution times. Note that the "Time(%)" column is calculated
    using a summation of the "Total Time" column, and represents that
    range's percent of the execution time of the ranges listed,
    and not a percentage of the application wall or CPU execution time.
EOF
}

### BEGIN include inc_setup ###

EXIT_HELP=25
EXIT_DB=26
EXIT_NODATA=27

# Verify number of params
if [ $# -lt 1 ]
then
    print_usage ${BASH_SOURCE[0]}
    exit ${EXIT_HELP}
fi

# Set DB file
DATABASE="$1"

# Verify DB file exists
if [ ! -f "${DATABASE}" ]
then
    exit ${EXIT_DB}
fi

# Verify DB file contents
# The sqlite3 file format is defined at https://sqlite.org/fileformat.html
DB_FILE_HEADER=$(head -c 16 "$DATABASE" | tr '\0' '\n')
if [ "${DB_FILE_HEADER}" != "SQLite format 3" ]
then
    exit ${EXIT_DB}
fi

# Helper function for error messages
function echoerr() # accepts multiple args
{
    echo "$@" >&2
}

# Setup standard vars

# If we were run by nsys, the path to the preferred sqlite3 should have been
# passed as an env-var.  If not, hope the user has it in their path.
SQLITE3="${NSYS_STATS_SCRIPTS_SQLITE:-sqlite3}"
SQLITE3OPTS="-header -csv -readonly"

RUN_SQLITE="eval \"${SQLITE3}\" ${SQLITE3OPTS} \"${DATABASE}\""

### END include inc_setup ###

### BEGIN: include from inc_table_exists ###

TABLE_EXISTS_TABLES=( )

function table_exists()
{
    local TABLE_NAME=$1

    if [ "${#TABLE_EXISTS_TABLES[@]}" -eq 0 ]
    then
        TABLE_EXISTS_TABLES=( $("${SQLITE3}" ${SQLITE3OPTS} "${DATABASE}" \
                "SELECT name FROM sqlite_master WHERE type = 'table' OR type = 'view'") )
    fi

    for TABLE in "${TABLE_EXISTS_TABLES[@]}"
    do
        if [ "${TABLE}" = "${TABLE_NAME}" ]
        then
            echo "true"
            return 1
        fi
    done
    echo "false"
    return 0
}

### END: include from inc_table_exists ###


if ! $(table_exists "NVTX_EVENTS")
then
    echoerr "${DATABASE} does not contain NV Tools Extension (NVTX) data."
    exit ${EXIT_NODATA}
fi

EVENT_TYPE_DOMAIN_ID=75

${RUN_SQLITE} << EOF

WITH
    domains AS (
        SELECT
            domainId AS id,
            text AS name
        FROM
            NVTX_EVENTS
        WHERE
            eventType = ${EVENT_TYPE_DOMAIN_ID}
    ),
    maxts AS(
        SELECT max(max(start), max(end)) AS m
        FROM   NVTX_EVENTS
    ),
    nvtx AS (
        SELECT
            coalesce(ne.end, (SELECT m FROM maxts)) - ne.start AS duration,
            CASE
                WHEN d.name NOT NULL AND sid.value IS NOT NULL
                    THEN d.name || ':' || sid.value
                WHEN d.name NOT NULL AND sid.value IS NULL
                    THEN d.name || ':' || ne.text
                WHEN d.name IS NULL AND sid.value NOT NULL
                    THEN sid.value
                ELSE ne.text
            END AS tag
        FROM
            NVTX_EVENTS AS ne
        LEFT OUTER JOIN
            domains AS d
            ON (ne.domainId = d.id)
        LEFT OUTER JOIN
            StringIds AS sid
            ON (ne.textId = sid.id)
        WHERE
            (ne.eventType = 59 OR ne.eventType = 70)
    ),
    summary AS (
        SELECT
            tag AS name,
            sum(duration) AS total,
            count(*) AS num,
            avg(duration) AS avg,
            min(duration) AS min,
            max(duration) AS max
        FROM
            nvtx
        GROUP BY 1
    ),
    totals AS (
        SELECT sum(total) AS total
        FROM summary
    )

    SELECT
        round(total * 100.0 / (SELECT total FROM totals), 1) AS "Time(%)",
        total AS "Total Time (ns)",
        num AS "Instances",
        round(avg, 1) AS "Average",
        min AS "Minimum",
        max AS "Maximum",
        name AS "Range"
    FROM
        summary
    ORDER BY 2 DESC
;
EOF
