warbo-utilities: d9bde68023024894de533152ca58ad08b404e413

     1: #! /usr/bin/env nix-shell
     2: #! nix-shell -i bash -p bash bc pv
     3: set -e
     4: # Analyse results of proc_trace.sh
     5: 
     6: function msg {
     7:     echo -e "$*" 1>&2
     8: }
     9: 
    10: msg "Reading input..."
    11: INPUT=$(cat | grep -e "^\\(\\[\\|[0-9]\\)")
    12: msg "Finished reading input"
    13: 
    14: # PID to use for the top-level process
    15: TOP=0
    16: function get_top_pid {
    17:     # Guess the top-level PID as the one which has no clone line
    18:     while read -r PIDGTP
    19:     do
    20:         if echo "$INPUT" | grep -q "clone(.*) = $PIDGTP"
    21:         then
    22:             true # no-op
    23:         else
    24:             TOP="$PIDGTP"
    25:             return
    26:         fi
    27:     done < <(echo "$INPUT" | grep -o "^\\[pid *[0-9]*\\]" | grep -o "[0-9]*")
    28: }
    29: 
    30: msg "Finding top-level process ID"
    31: get_top_pid
    32: msg "Found top-level PID: $TOP"
    33: 
    34: function strip_prefix {
    35:     echo "$1" | sed -e 's/\[pid *[0-9]*\] //g'
    36: }
    37: 
    38: function pid_of {
    39:     # Try to infer which process a line comes from. This is either a [pid 1234]
    40:     # prefix, or no prefix if the line comes from the top process
    41:     if PRE=$(echo "$1" | grep -o "^\\[pid *[0-9]*\\]")
    42:     then
    43:         echo "$PRE" | grep -o "[0-9]*"
    44:     else
    45:         echo "$TOP"
    46:     fi
    47: }
    48: 
    49: function lines_of {
    50:     # Returns lines associated with the given PID
    51:     if [[ "$1" -eq "$TOP" ]]
    52:     then
    53:         echo "$INPUT" | grep -v "^\\[pid *[0-9]*\\]"
    54:     else
    55:         echo "$INPUT" | grep "^\\[pid *$1\\]"
    56:     fi
    57: }
    58: 
    59: function time_of {
    60:     # Get the timestamp from a line
    61:     echo "$1" | sed -e 's/\[pid *[0-9]*\] //g' | cut -d ' ' -f 1
    62: }
    63: 
    64: function find_creation {
    65:     # Find the line (if any) where the given PID was spawned
    66:     echo "$INPUT" | grep "clone(.*) = $1" | head -n1
    67: }
    68: 
    69: function creation_time {
    70:     if [[ "$1" -eq "$TOP" ]]
    71:     then
    72:         time_of "$(echo "$INPUT" | head -n1)"
    73:     else
    74:         time_of "$(find_creation "$1")"
    75:     fi
    76: }
    77: 
    78: function find_destruction {
    79:     # Find the line (if any) where the given PID exited
    80:     if [[ "$1" -eq "$TOP" ]]
    81:     then
    82:         # The top process exits on the last line
    83:         echo "$INPUT" | tail -n1
    84:     else
    85:         lines_of "$1" | grep "+++ exited with"
    86:     fi
    87: }
    88: 
    89: function destruction_time {
    90:     time_of "$(find_destruction "$1")"
    91: }
    92: 
    93: function contains_element {
    94:     # Taken from http://stackoverflow.com/a/8574392/884682
    95:     local e
    96:     for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    97:     return 1
    98: }
    99: 
   100: function gte {
   101:     # $1 >= $2
   102:     (( $(echo "$1 >= $2" | bc -l) ))
   103: }
   104: 
   105: function all_creations {
   106:     echo "$INPUT" | grep "clone("
   107: }
   108: 
   109: function all_destructions {
   110:     echo "$INPUT" | grep "+++ exited with"
   111: }
   112: 
   113: function all_lines {
   114:     # We only care about creations and destructions
   115:     all_creations
   116:     all_destructions
   117: }
   118: 
   119: function all_times {
   120:     # All times, in order
   121:     all_lines | sed -e 's/\[pid *[0-9]*\] //g' | cut -d ' ' -f 1 | sort -gu
   122: }
   123: msg "Getting all times"
   124: ALL_TIMES=$(all_times)
   125: msg "Got all times"
   126: 
   127: function pid_col {
   128:     C=$(creation_time    "$1")
   129:     D=$(destruction_time "$1")
   130: 
   131:     if [[ -z "$C" ]]
   132:     then
   133:         C=$(echo "$ALL_TIMES" | head -n1)
   134:     fi
   135: 
   136:     if [[ -z "$D" ]]
   137:     then
   138:         D=$(echo "$ALL_TIMES" | tail -n1)
   139:     fi
   140: 
   141:     STARTED=0
   142:     STOPPED=0
   143:     while read -r TIM
   144:     do
   145:         if [[ "$STOPPED" -eq 1 ]]
   146:         then
   147:             echo 0
   148:             continue
   149:         fi
   150: 
   151:         if  [[ "$STARTED" -eq 0 ]]
   152:         then
   153:             if gte "$C" "$TIM"
   154:             then
   155:                 echo "0"
   156:             else
   157:                 STARTED=1
   158:                 echo "1"
   159:             fi
   160:         else
   161:             if gte "$TIM" "$D"
   162:             then
   163:                 STOPPED=1
   164:                 echo "0"
   165:             else
   166:                 echo "1"
   167:             fi
   168:         fi
   169:     done < <(echo "$ALL_TIMES")
   170: }
   171: 
   172: function pid_cols {
   173:     GOT_COLS="$ALL_TIMES"
   174:     THIS_COUNT=1
   175:     for PIDC in "${PIDS[@]}"
   176:     do
   177:         GOT_COLS=$(paste -d "," <(echo "$GOT_COLS") <(pid_col "$PIDC"))
   178:         THIS_COUNT=$(( THIS_COUNT + 1 ))
   179:         msg "$THIS_COUNT/$PID_COUNT"
   180:     done 2> >(pv -etpl -s "$TIMES" > /dev/null)
   181:     echo "$GOT_COLS"
   182: }
   183: 
   184: function get_all_pids {
   185:     # Fill PIDS with all PIDs that were logged
   186:     echo "$TOP"
   187:     echo "$INPUT" | grep -o '\[pid *[0-9]*\]' | grep -o '[0-9]*' | sort -u
   188: }
   189: 
   190: msg "Looking up all process IDs"
   191: readarray -t PIDS < <(get_all_pids)
   192: msg "Got all PIDs"
   193: 
   194: function name_of {
   195:     FOUND=$(lines_of "$1" |
   196:                    grep "execve(" |
   197:                    grep -o 'execve("[^"]*"' |
   198:                    sed -e 's/^execve(//g' | sed -e 's/,//g' |
   199:                    head -n1)
   200:     if [[ -n "$FOUND" ]]
   201:     then
   202:         echo "$FOUND"
   203:     else
   204:         echo "Unknown"
   205:     fi
   206: }
   207: 
   208: function make_heading {
   209:     printf "Time,"
   210:     for PIDMH in "${PIDS[@]}"
   211:     do
   212:         COL=$(name_of "$PIDMH")
   213:         printf "%s," "$COL"
   214:     done
   215:     echo ""
   216: }
   217: 
   218: function rows_with_heading {
   219:     printf "Heading..." 1>&2
   220:     make_heading | tee >(tr , '\n' | pv -etls "$PID_COUNT" > /dev/null)
   221:     msg "Heading finished. Rows..."
   222:     pid_cols
   223:     msg "Rows finished"
   224: }
   225: 
   226: function make_csv {
   227:     rows_with_heading | sed -e 's/,$//g'
   228: }
   229: 
   230: PID_COUNT="${#PIDS[@]}"
   231: TIMES=$(echo "$ALL_TIMES" | wc -l)
   232: 
   233: msg "Making CSV"
   234: make_csv
   235: msg "Finished"

Generated by git2html.