Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v-jinmgong/emulation: Refactor emulation code for easier execution and alignment with the simulator api #2

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
runtime/dll
runtime/exe
__pycache__
log/
workdir/
47 changes: 47 additions & 0 deletions compress_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import re
import sys
import argparse
import os

def compress_logs(log_file, patterns, output_path):
patterns = [re.compile(pattern) for pattern in patterns]
if os.path.exists(output_path):
os.remove(output_path)
with open(output_path, 'w') as outfile:
with open(log_file, 'r') as infile:
for line in infile:
for pattern in patterns:
match = pattern.search(line)
if match:
outfile.write(line)
break
# get the output path with relative path from input path
def get_output_path(input_path, base_input_dir, base_output_dir):
relative_path = os.path.relpath(input_path, base_input_dir)
return os.path.join(base_output_dir, relative_path)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Process and compress log files.')
parser.add_argument('--receiver_log', type=str, required=True, help='receiver log file path')
parser.add_argument('--sender_log', type=str, required=True, help='sender log file path')
parser.add_argument('--receiver_patterns', type=lambda s: [p for p in s.split('|') if p], help='pipe-separated list of receiver log regex patterns')
parser.add_argument('--sender_patterns', type=lambda s: [p for p in s.split('|') if p], help='pipe-separated list of sender log regex patterns')
parser.add_argument('--base_input_dir', type=str, required=True, help='Base input directory')
parser.add_argument('--base_output_dir', type=str, required=True, help='Base output directory')

args = parser.parse_args()

receiver_log = args.receiver_log
sender_log = args.sender_log
receiver_patterns = args.receiver_patterns
sender_patterns = args.sender_patterns
base_input_dir = args.base_input_dir
base_output_dir = args.base_output_dir

output_path = get_output_path(receiver_log, base_input_dir, base_output_dir)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
compress_logs(receiver_log, receiver_patterns, output_path)

output_path = get_output_path(sender_log, base_input_dir, base_output_dir)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
compress_logs(sender_log, sender_patterns, output_path)
284 changes: 284 additions & 0 deletions emulation.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
#!/bin/bash

# Get the current terminal path
CURRENT_PATH=$(pwd)
echo "Current terminal path: $CURRENT_PATH"
# Get the current script path: emulation/emulation.sh
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")

# Default parameter values
DEFAULT_AUTOCLOSE=120
DEFAULT_VIDEO_HEIGHT=1080
DEFAULT_VIDEO_WIDTH=1920
DEFAULT_VIDEO_FPS=30
DEFAULT_IF_SAVE_MEDIA=true

# Patterns for compressing logs
RECEIVER_PATTERNS=(
"\(remote_estimator_proxy\.cc:\d+\): (\{.*\})"\
)

SENDER_PATTERNS=(
"\(rtp_transport_controller_send\.cc:\d+\): PostUpdates SetTargetRate: (\d+), PostUpdates SetTargetRate Time: (\d+)"\
"\(rtp_sender_egress\.cc:\d+\): RtpSenderEgress::SendPacket: packet ssrc: (\d+), sequence number: (\d+), timestamp: \d+, payload type: \d+, payload size: (\d+), packet_sendtime: (\d+) ms, packet_type: (-?\d+)" \
"\(video_stream_encoder\.cc:\d+\): Video frame parameters changed: dimensions=(\d+)x(\d+), texture=\d+ at time= (\d+)ms."
)
RECEIVER_PATTERNS_STR=$(printf "%s|" "${RECEIVER_PATTERNS[@]}")
SENDER_PATTERNS_STR=$(printf "%s|" "${SENDER_PATTERNS[@]}")
if [ -z "$RECEIVER_PATTERNS_STR" ] || [ -z "$SENDER_PATTERNS_STR" ]; then
echo "Error: receiver_patterns or sender_patterns is empty."
exit 1
fi

# Parse input parameters
while getopts "hm:v:a:t:c:W:H:f:s:l:" opt; do
case $opt in
h) echo "Usage: `basename $0` [-m model] [-v video_file] [-a audio_file][-t trace_file] [-c autoclose] [-W video_width] [-H video_height] [-f video_fps] [-s if_save_media] [-l log_dir]" >&2
exit 0 ;;
m) MODEL_DIR="$OPTARG" ;;
v) VIDEO_FILE="$OPTARG" ;;
a) AUDIO_FILE="$OPTARG" ;;
t) TRACE_FILE="$OPTARG" ;;
c) AUTOCLOSE="$OPTARG" ;;
W) VIDEO_WIDTH="$OPTARG" ;;
H) VIDEO_HEIGHT="$OPTARG" ;;
f) VIDEO_FPS="$OPTARG" ;;
s) IF_SAVE_MEDIA="$OPTARG" ;;
l) LOG_DIR="$OPTARG" ;;
\?) echo "Invalid option: -$OPTARG" >&2
exit 1 ;;
:) echo "Option -$OPTARG requires an argument." >&2
exit 1 ;;
esac
done

# Set default values
AUTOCLOSE=${AUTOCLOSE:-$DEFAULT_AUTOCLOSE}
VIDEO_WIDTH=${VIDEO_WIDTH:-$DEFAULT_VIDEO_WIDTH}
VIDEO_HEIGHT=${VIDEO_HEIGHT:-$DEFAULT_VIDEO_HEIGHT}
VIDEO_FPS=${VIDEO_FPS:-$DEFAULT_VIDEO_FPS}
IF_SAVE_MEDIA=${IF_SAVE_MEDIA:-$DEFAULT_IF_SAVE_MEDIA}

# Other directory settings
WORKDIR="${SCRIPT_DIR}/workdir"
DLL_PATH="${SCRIPT_DIR}/runtime/dll"
CMDINFER_PATH="${SCRIPT_DIR}/runtime/pyinfer/cmdinfer"
PYINFER_PATH="${SCRIPT_DIR}/runtime/pyinfer/cmdinfer/peerconnection_serverless"
GCC_PATH="${SCRIPT_DIR}/runtime/exe/peerconnection_gcc"
# Generate media config
generate_media_config() {
local video_file=$1
local audio_file=$2
local save_video=$3
local save_audio=$4
local receiver_logging=$5
local sender_logging=$6
local receiver_output=$7
local sender_output=$8
local listening_port=$((RANDOM % 800 + 8000))

python3 ${SCRIPT_DIR}/set_media_config.py \
--autoclose "$AUTOCLOSE" \
--listening_ip "0.0.0.0" \
--listening_port "$listening_port" \
--bwe_feedback_duration 200 \
--video_file "$video_file" \
--audio_file "$audio_file" \
--save_video "$save_video" \
--save_audio "$save_audio" \
--receiver_logging "$receiver_logging" \
--sender_logging "$sender_logging" \
--receiver_output "$receiver_output" \
--sender_output "$sender_output" \
--video_height "$VIDEO_HEIGHT" \
--video_width "$VIDEO_WIDTH" \
--video_fps "$VIDEO_FPS" \
--if_save_media "$IF_SAVE_MEDIA"
}

# Calculate score for video and network
calculate_score() {
local receiver_log=$1
local src_video=$2
local dst_video=$3
local output_file=$4

python3 ${SCRIPT_DIR}/metrics/eval_video.py \
--src_video "$src_video" \
--dst_video "$dst_video" \
--output "$output_file" \
--frame_align_method "ocr" \
--video_size "${VIDEO_WIDTH}x${VIDEO_HEIGHT}" \
--pixel_format "420" \
--bitdepth "8" \
--fps "$VIDEO_FPS"

python3 ${SCRIPT_DIR}/metrics/eval_network.py \
--dst_network_log "$receiver_log" \
--output "$output_file"
}

# Compress logs according to patterns
compress_logs() {
local receiver_log=$1
local sender_log=$2
local base_input_dir=$3
local base_output_dir=$4

python3 ${SCRIPT_DIR}/compress_logs.py \
--receiver_log "$receiver_log" \
--sender_log "$sender_log" \
--receiver_patterns "$RECEIVER_PATTERNS_STR" \
--sender_patterns "$SENDER_PATTERNS_STR" \
--base_input_dir "$base_input_dir" \
--base_output_dir "$base_output_dir"
}

# Clean runtime directory after changing the run model
clean_runtime_dir() {
find "$CMDINFER_PATH" -type f ! -name 'cmdinfer.cc' ! -name 'cmdinfer.h' ! -name 'cmdinfer.py' ! -name 'peerconnection_serverless' -delete
find "$CMDINFER_PATH" -type d -mindepth 1 -exec rm -r {} +
}

# Main loop
emulation(){

printf "Starting transmission\n"
# Ban other network access
sudo ifconfig docker0 down
sudo ifconfig enP65263s1 down
sudo iptables -A INPUT -i eth0 -s 10.0.0.0/8 -p udp -j DROP
sudo iptables -A OUTPUT -o eth0 -d 10.0.0.0/8 -p udp -j DROP
printf "Ban other network access\n"
# Mount tmpfs for faster I/O read/write operations
mkdir -p "$WORKDIR"
while mountpoint -q media; do
sudo umount media --force
done
printf "Successfully unmounted tmpfs\n"
printf "Mounting tmpfs\n"
sudo mount -t tmpfs -o size=24G media "$WORKDIR"

rm -r "$WORKDIR"/*
printf "Cleared workdir\n"

if [ -f "$TRACE_FILE" ]; then
trace_name=$(basename "$TRACE_FILE" .json)
trace_dir="$WORKDIR/$trace_name"
mkdir -p "$trace_dir"
printf "Created trace directory\n"
receiver_logging="$trace_dir/receiver.log"
sender_logging="$trace_dir/sender.log"
save_video="$trace_dir/outvideo.yuv"
save_audio="$trace_dir/outaudio.wav"
receiver_output="$trace_dir/receiver_config.json"
sender_output="$trace_dir/sender_config.json"
printf "Applying network configuration\n"
python3 ${SCRIPT_DIR}/tc_setup.py --config "$TRACE_FILE" &
network_pid=$!
sleep 10
fi
if [ -f "$VIDEO_FILE" ] && [ -f "$AUDIO_FILE" ]; then
base_name=$(basename "$VIDEO_FILE" .yuv)
workdir_audio="$WORKDIR/$base_name.wav"
cp "$AUDIO_FILE" "$workdir_audio"
fi
if [ "$MODEL_DIR" == "gcc" ]; then
# Convert video file to y4m format using ffmpeg, because the original yuv format is not supported by the gcc_baseline
ffmpeg -s ${VIDEO_WIDTH}x${VIDEO_HEIGHT} -pix_fmt yuv420p -r $VIDEO_FPS -i "$VIDEO_FILE" -vsync 0 "$WORKDIR/$base_name.y4m"
workdir_video="$WORKDIR/$base_name.y4m"
printf "Copied video and audio files\n"
printf "Generated media config\n"
generate_media_config "$workdir_video" "$workdir_audio" "$save_video" "$save_audio" "$receiver_logging" "$sender_logging" "$receiver_output" "$sender_output"

printf "Starting transmission\n"
printf "Running model: gcc, video: %s, trace: %s\n" "$base_name" "$trace_name"
$GCC_PATH $receiver_output &
receiver_pid=$!
sleep 20
$GCC_PATH $sender_output
sender_pid=$!
wait $receiver_pid
printf "Transmission finished\n"

elif [ -d "$MODEL_DIR" ]; then
workdir_video="$WORKDIR/$base_name.yuv"
cp "$VIDEO_FILE" "$workdir_video"
printf "Copied video and audio files\n"
printf "Generated media config\n"
generate_media_config "$workdir_video" "$workdir_audio" "$save_video" "$save_audio" "$receiver_logging" "$sender_logging" "$receiver_output" "$sender_output"

model_name=$(basename "$MODEL_DIR")
clean_runtime_dir
printf "Cleaned runtime directory\n"
printf "Copying model files\n"
cp -rf "$MODEL_DIR"/* "$CMDINFER_PATH"
printf "Model files copied\n"
cd $CMDINFER_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DLL_PATH

printf "Starting transmission\n"
printf "Running model: %s, video: %s, trace: %s\n" "$model_name" "$base_name" "$trace_name"
python3 $PYINFER_PATH $receiver_output &
receiver_pid=$!
sleep 20 # Wait for the receiver to set up
python3 $PYINFER_PATH $sender_output
sender_pid=$!
wait $receiver_pid
printf "Transmission finished\n"
fi
# Terminate network configuration process
while kill -0 $network_pid 2>/dev/null; do
sudo kill -9 $network_pid
done
echo "The network configuration process $network_pid has been terminated"
sleep 10

# Post-process logs: calculate score and compress logs
printf "Calculating score\n"
model_name=${model_name:-gcc}
store_dir="$LOG_DIR/$base_name/$trace_name/$model_name"
mkdir -p "$store_dir"
if [ -f "$store_dir/score.json" ]; then
: > "$store_dir/score.json"
else
touch "$store_dir/score.json"
fi
calculate_score "$receiver_logging" "$workdir_video" "$save_video" "$store_dir/score.json"
printf "Score calculated\n"
printf "Compressing logs\n"
compress_logs "$receiver_logging" "$sender_logging" "$trace_dir" "$store_dir"
printf "Logs compressed and moved\n"

# Clean up
rm -r "$trace_dir"/*
printf "Cleared transmission outputs\n"

sudo umount media --force
while mountpoint -q media; do
sudo umount media --force
done
printf "Successfully unmounted tmpfs\n"
printf "Transmission finished\n"
}

# Main function
main() {
# Your main logic here
echo "Running main function with the following parameters:"
echo "MODEL_DIR: $MODEL_DIR"
echo "VIDEO_FILE: $VIDEO_FILE"
echo "AUDIO_FILE: $AUDIO_FILE"
echo "TRACE_FILE: $TRACE_FILE"
echo "AUTOCLOSE: $AUTOCLOSE"
echo "VIDEO_WIDTH: $VIDEO_WIDTH"
echo "VIDEO_HEIGHT: $VIDEO_HEIGHT"
echo "VIDEO_FPS: $VIDEO_FPS"
echo "IF_SAVE_MEDIA: $IF_SAVE_MEDIA"
echo "LOG_DIR: $LOG_DIR"
emulation
# Add the rest of your script logic here
}

# Call main function if parameter parsing was successful
main
Loading