#!/bin/bash

# Reproduce the 3-party Circuit ORAM experiments from our paper:

# Adithya Vadapalli, Ryan Henry, Ian Goldberg. Duoram: A
# Bandwidth-Efficient Distributed ORAM for 2- and 3-Party Computation.
# USENIX Security Symposium 2023.

# cd into the directory containing this script (from the bash faq 028)
if [[ $BASH_SOURCE = */* ]]; then
  cd -- "${BASH_SOURCE%/*}/" || exit
fi

# If the Duoram NUMA commands are set, but Circuit-ORAM-specific ones are not,
# use them for Circuit ORAM.
if [ "$ORAM_NUMA_C" == "" -a "$DUORAM_NUMA_P0" != "" ]; then
    export ORAM_NUMA_C="$DUORAM_NUMA_P0"
fi
if [ "$ORAM_NUMA_D" == "" -a "$DUORAM_NUMA_P1" != "" ]; then
    export ORAM_NUMA_D="$DUORAM_NUMA_P1"
fi
if [ "$ORAM_NUMA_E" == "" -a "$DUORAM_NUMA_P2" != "" ]; then
    export ORAM_NUMA_E="$DUORAM_NUMA_P2"
fi

# Allow running only subsets of the experiment suite.  Valid values are
# "test", "small", "large", "all", "none".  ("none" is useful if you
# just want to re-parse the output of existing logs.)  You can also say
# "single" followed by all the arguments to "run" (below) to run a
# single experiment; for example:
# ./repro single 20 1us 100gbit 128
if [ "$1" = "" ]; then
    whichexps="test"
else
    whichexps="$1"
fi

# The number of operations per run; the graphs in the paper use 128
if [ "$whichexps" = "single" -o "$2" = "" ]; then
    # If there's an explicit experiment on the command line, don't read
    # the next argument as the number of operations.  $numops will be
    # ignored, anyway, since it will be specified as part of the
    # command.
    numops=128
else
    numops="$2"
fi

# Run one experiment
# Arguments:
# $1: depth (the ORAM has 2^depth elements)
# $2: latency (e.g., 30ms)
# $3: bandwidth (e.g., 100mbit)
# $4: number of operations (e.g., 128)
run() {
    now=`date`
    echo "$now: Running $1 $2 $3 $4 ..."
    logfile="read_${2}_${3}_${4}.out${LOGSUFFIX}"
    ./set-networking $2 $3
    echo "Network setup: $2 $3" >> $logfile
    ./run-experiment $1 $4 >> $logfile
}

# Parse the output logs.  We run this in the docker in case you don't
# have perl installed on the host.
# Arguments: a list of logfiles
parse() {
    if [ "$ORAM_PARSE_HOST" = "1" ]; then
        ./parse_logs $*
    else
        cat $* | docker exec -w /root/oram/docker -i oram_C ./parse_logs
    fi
}

# A very small kick-the-tires test to ensure everything compiled and
# built properly
if [ "$whichexps" = "test" ]; then
    echo "Running test experiment..."
    run 16 1us 100gbit 2
    echo
    echo "# Test output"
    echo
    parse read_1us_100gbit_2.out${LOGSUFFIX}
    echo
    echo "# End test output"
    echo
    exit
fi

# Be able to run a single experiment specified on the command line
if [ "$whichexps" = "single" ]; then
    echo "Running single experiment..."
    shift
    run $*
    exit
fi

now=`date`
echo "$now: Starting experiments"

if [ "$whichexps" = "small" -o "$whichexps" = "all" ]; then
    echo "Running small experiments..."
    # Figure 9(a)
    run 16 30ms 100mbit ${numops}
    run 18 30ms 100mbit ${numops}
    run 20 30ms 100mbit ${numops}
    run 22 30ms 100mbit ${numops}
    run 24 30ms 100mbit ${numops}
    run 26 30ms 100mbit ${numops}
    # Figures 9(b) and 9(c)
    # Note that we set the latency to 1us, which really means "don't add
    # artificial latency", but we measure the one-way latency to
    # actually be 30us, which is what we report in the paper. (pings
    # from one docker to the other take about 60us round trip.)
    run 16 1us 100gbit ${numops}
    run 18 1us 100gbit ${numops}
    run 20 1us 100gbit ${numops}
    run 22 1us 100gbit ${numops}
    run 24 1us 100gbit ${numops}
    run 26 1us 100gbit ${numops}
fi
if [ "$whichexps" = "large" -o "$whichexps" = "all" ]; then
    echo "Running large experiments..."
    # Figure 9(a)
    run 28 30ms 100mbit ${numops}
    run 30 30ms 100mbit ${numops}
    run 32 30ms 100mbit ${numops}
    # Figures 9(b) and 9(c)
    run 28 1us 100gbit ${numops}
    run 30 1us 100gbit ${numops}
    run 32 1us 100gbit ${numops}
fi

now=`date`
echo "$now: Experiments complete"

# If you specified a custom log suffix, you're going to be parsing the
# outputs differently.
if [ "$LOGSUFFIX" = "" ]; then

parse *_${numops}.out > oram_${numops}.dat

echo
echo "# Figure 9(a)"
egrep 'CircuitORAMOnln read .* 30ms 100mbit .* s$' oram_${numops}.dat | sort -k3 -n
echo
egrep 'CircuitORAMTotl read .* 30ms 100mbit .* s$' oram_${numops}.dat | sort -k3 -n
echo
echo "# Figure 9(b)"
egrep 'CircuitORAMOnln read .* 1us 100gbit .* s$' oram_${numops}.dat | sort -k3 -n
echo
egrep 'CircuitORAMTotl read .* 1us 100gbit .* s$' oram_${numops}.dat | sort -k3 -n
echo
echo "# Figure 9(c)"
egrep 'CircuitORAMOnln read .* 1us 100gbit .* KiB$' oram_${numops}.dat | sort -k3 -n
echo
egrep 'CircuitORAMTotl read .* 1us 100gbit .* KiB$' oram_${numops}.dat | sort -k3 -n
echo
echo "# End figures"

fi