1#!/usr/bin/env bash
2# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3#
4# A shell script to run a batch of pysims and combine individual pysim output files.
5#
6# Usage: bash block_cache_pysim.sh trace_file_path result_dir downsample_size warmup_seconds max_jobs
7# trace_file_path: The file path that stores the traces.
8# result_dir: The directory to store pysim results. The output files from a pysim is stores in result_dir/ml
9# downsample_size: The downsample size used to collect the trace.
10# warmup_seconds: The number of seconds used for warmup.
11# max_jobs: The max number of concurrent pysims to run.
12
13# Install required packages to run simulations.
14# sudo dnf install -y numpy scipy python-matplotlib ipython python-pandas sympy python-nose atlas-devel
15ulimit -c 0
16
17if [ $# -ne 5 ]; then
18  echo "Usage: ./block_cache_pysim.sh trace_file_path result_dir downsample_size warmup_seconds max_jobs"
19  exit 0
20fi
21
22trace_file="$1"
23result_dir="$2"
24downsample_size="$3"
25warmup_seconds="$4"
26max_jobs="$5"
27max_num_accesses=100000000
28current_jobs=1
29
30ml_tmp_result_dir="$result_dir/ml"
31rm -rf "$ml_tmp_result_dir"
32mkdir -p "$result_dir"
33mkdir -p "$ml_tmp_result_dir"
34
35# Report miss ratio in the trace.
36current_jobs=$(ps aux | grep pysim | grep python | grep -cv grep)
37for cf_name in "all"
38do
39for cache_size in "1G" "2G" "4G" "8G" "16G" #"12G" "16G" "1T"
40do
41for cache_type in "opt" "lru" "pylru" "pycctbbt" "pyhb" "ts" "trace" "lru_hybrid"  #"pycctblevelbt" #"lru_hybridn" "opt" #"pylru" "pylru_hybrid" "pycctbbt" "pycccfbt" "trace"
42do
43    if [[ $cache_type == "trace" && $cache_size != "16G" ]]; then
44      # We only need to collect miss ratios observed in the trace once.
45      continue
46    fi
47    while [ "$current_jobs" -ge "$max_jobs" ]
48    do
49      sleep 10
50      echo "Waiting jobs to complete. Number of running jobs: $current_jobs"
51      current_jobs=$(ps aux | grep pysim | grep python | grep -cv grep)
52      echo "Waiting jobs to complete. Number of running jobs: $current_jobs"
53    done
54    output="log-ml-$cache_type-$cache_size-$cf_name"
55    echo "Running simulation for $cache_type, cache size $cache_size, and cf_name $cf_name. Number of running jobs: $current_jobs. "
56    nohup python block_cache_pysim.py "$cache_type" "$cache_size" "$downsample_size" "$warmup_seconds" "$trace_file" "$ml_tmp_result_dir" "$max_num_accesses" "$cf_name" >& "$ml_tmp_result_dir/$output" &
57    current_jobs=$((current_jobs+1))
58done
59done
60done
61
62# Wait for all jobs to complete.
63while [ $current_jobs -gt 0 ]
64do
65  sleep 10
66  echo "Waiting jobs to complete. Number of running jobs: $current_jobs"
67  current_jobs=$(ps aux | grep pysim | grep python | grep -cv grep)
68  echo "Waiting jobs to complete. Number of running jobs: $current_jobs"
69done
70
71echo "Combine individual pysim output files"
72
73rm -rf "$result_dir/ml_*"
74for header in "header-" "data-"
75do
76for fn in "$ml_tmp_result_dir"/*
77do
78  sum_file=""
79  time_unit=""
80  capacity=""
81  target_cf_name=""
82  if [[ $fn == *"timeline"* ]]; then
83    tmpfn="$fn"
84    IFS='-' read -ra elements <<< "$tmpfn"
85    time_unit_index=0
86    capacity_index=0
87    for i in "${elements[@]}"
88    do
89       if [[ $i == "timeline" ]]; then
90         break
91       fi
92       time_unit_index=$((time_unit_index+1))
93    done
94    time_unit_index=$((time_unit_index+1))
95    capacity_index=$((time_unit_index+2))
96    target_cf_name_index=$((time_unit_index+3))
97    time_unit="${elements[$time_unit_index]}_"
98    capacity="${elements[$capacity_index]}_"
99    target_cf_name="${elements[$target_cf_name_index]}_"
100  fi
101
102  if [[ $fn == *"${header}ml-policy-timeline"* ]]; then
103    sum_file="$result_dir/ml_${target_cf_name}${capacity}${time_unit}policy_timeline"
104  fi
105  if [[ $fn == *"${header}ml-policy-ratio-timeline"* ]]; then
106    sum_file="$result_dir/ml_${target_cf_name}${capacity}${time_unit}policy_ratio_timeline"
107  fi
108  if [[ $fn == *"${header}ml-miss-timeline"* ]]; then
109    sum_file="$result_dir/ml_${target_cf_name}${capacity}${time_unit}miss_timeline"
110  fi
111  if [[ $fn == *"${header}ml-miss-ratio-timeline"* ]]; then
112    sum_file="$result_dir/ml_${target_cf_name}${capacity}${time_unit}miss_ratio_timeline"
113  fi
114  if [[ $fn == *"${header}ml-mrc"* ]]; then
115    tmpfn="$fn"
116    IFS='-' read -ra elements <<< "$tmpfn"
117    target_cf_name=${elements[-1]}
118    sum_file="${result_dir}/ml_${target_cf_name}_mrc"
119  fi
120  if [[ $fn == *"${header}ml-avgmb"* ]]; then
121    tmpfn="$fn"
122    IFS='-' read -ra elements <<< "$tmpfn"
123    time_unit=${elements[3]}
124    target_cf_name=${elements[-1]}
125    sum_file="${result_dir}/ml_${time_unit}_${target_cf_name}_avgmb"
126  fi
127  if [[ $fn == *"${header}ml-p95mb"* ]]; then
128    tmpfn="$fn"
129    IFS='-' read -ra elements <<< "$tmpfn"
130    time_unit=${elements[3]}
131    target_cf_name=${elements[-1]}
132    sum_file="${result_dir}/ml_${time_unit}_${target_cf_name}_p95mb"
133  fi
134  if [[ $sum_file == "" ]]; then
135    continue
136  fi
137  if [[ $header == "header-" ]]; then
138    if [ -e "$sum_file" ]; then
139      continue
140    fi
141  fi
142  cat "$fn" >> "$sum_file"
143done
144done
145
146echo "Done"
147for fn in $result_dir/*
148do
149  if [[ $fn == *"_mrc" || $fn == *"_avgmb" || $fn == *"_p95mb" ]]; then
150    # Sort MRC file by cache_type and cache_size.
151    tmp_file="$result_dir/tmp_mrc"
152    cat "$fn" | sort -t ',' -k1,1 -k4,4n > "$tmp_file"
153    cat "$tmp_file" > "$fn"
154    rm -rf "$tmp_file"
155  fi
156done
157