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.