| 1 | # Copyright (C) 2018 - Francis Deslauriers <francis.deslauriers@efficios.com> |
| 2 | # |
| 3 | # This program is free software: you can redistribute it and/or modify |
| 4 | # it under the terms of the GNU General Public License as published by |
| 5 | # the Free Software Foundation, either version 3 of the License, or |
| 6 | # (at your option) any later version. |
| 7 | # |
| 8 | # This program is distributed in the hope that it will be useful, |
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | # GNU General Public License for more details. |
| 12 | # |
| 13 | # You should have received a copy of the GNU General Public License |
| 14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 15 | |
| 16 | import datetime |
| 17 | import gzip |
| 18 | import os |
| 19 | import pprint |
| 20 | import subprocess |
| 21 | import sys |
| 22 | |
| 23 | NB_KPROBES_PER_ITER=500 |
| 24 | |
| 25 | def load_instr_points(instr_points_archive): |
| 26 | print('Reading instrumentation points from \'{}\'.'.format(instr_points_archive), end='') |
| 27 | sys.stdout.flush() |
| 28 | |
| 29 | with gzip.open(instr_points_archive, 'r') as f: |
| 30 | data = f.read() |
| 31 | print(' Done.') |
| 32 | |
| 33 | return [x.decode('utf-8') for x in data.split()] |
| 34 | |
| 35 | def enable_kprobe_events(instr_points): |
| 36 | print('Enabling events from {} to {}...'.format(instr_points[0], instr_points[-1]), end='') |
| 37 | sys.stdout.flush() |
| 38 | |
| 39 | # Use os module directly, because this is a sysfs file and seeking inside |
| 40 | # the file is not supported. The python open() function with the append |
| 41 | # ('a') flag uses lseek(, SEEK_END) to move the write pointer to the end. |
| 42 | fd = os.open('/sys/kernel/debug/tracing/kprobe_events', os.O_WRONLY|os.O_CREAT|os.O_APPEND) |
| 43 | for i, point in enumerate(instr_points): |
| 44 | |
| 45 | kprobe_cmd = 'r:event_{} {}\n'.format(i, point).encode('utf-8') |
| 46 | try: |
| 47 | os.write(fd, kprobe_cmd) |
| 48 | except OSError: |
| 49 | continue |
| 50 | os.close(fd) |
| 51 | print(' Done.') |
| 52 | |
| 53 | def set_kprobe_tracing_state(state): |
| 54 | if state not in (0 ,1): |
| 55 | raise ValueError |
| 56 | |
| 57 | if state == 0: |
| 58 | # Clear the content of the trace. |
| 59 | open('/sys/kernel/debug/tracing/trace', 'w').close() |
| 60 | |
| 61 | try: |
| 62 | with open('/sys/kernel/debug/tracing/events/kprobes/enable', 'w') as enable_kprobe_file: |
| 63 | enable_kprobe_file.write('{}\n'.format(state)) |
| 64 | except IOError: |
| 65 | print('kprobes/enable file does not exist') |
| 66 | |
| 67 | def run_workload(): |
| 68 | print('Running workload...', end='') |
| 69 | sys.stdout.flush() |
| 70 | workload = ['stress', '--cpu', '2', '--io', '4', '--vm', '2', |
| 71 | '--vm-bytes', '128M', '--hdd', '3', '--timeout', '3s'] |
| 72 | try: |
| 73 | with open(os.devnull) as devnull: |
| 74 | subprocess.call(workload, stdout=devnull, stderr=devnull) |
| 75 | except OSError as e: |
| 76 | print("Workload execution failed:", e, file=sys.stderr) |
| 77 | pprint.pprint(workload) |
| 78 | |
| 79 | print(' Done.') |
| 80 | |
| 81 | def mount_tracingfs(): |
| 82 | with open(os.devnull) as devnull: |
| 83 | subprocess.call(['mount', '-t', 'debugfs', 'nodev', '/sys/kernel/debug/'], |
| 84 | stdout=devnull, stderr=devnull) |
| 85 | |
| 86 | def print_dashed_line(): |
| 87 | print('-'*100) |
| 88 | |
| 89 | def main(): |
| 90 | assert(len(sys.argv) == 2) |
| 91 | |
| 92 | instr_point_archive = sys.argv[1] |
| 93 | # Load instrumentation points to disk and attach it to lava test run. |
| 94 | instrumentation_points = load_instr_points(instr_point_archive) |
| 95 | |
| 96 | mount_tracingfs() |
| 97 | |
| 98 | # Loop over the list by enabling ranges of NB_KPROBES_PER_ITER kprobes. |
| 99 | for i in range(int(len(instrumentation_points)/NB_KPROBES_PER_ITER)): |
| 100 | print_dashed_line() |
| 101 | print('Time now: {}, {} to {}'.format(datetime.datetime.now(), i*NB_KPROBES_PER_ITER, (i+1)*NB_KPROBES_PER_ITER)) |
| 102 | set_kprobe_tracing_state(0) |
| 103 | enable_kprobe_events(instrumentation_points[i*NB_KPROBES_PER_ITER:(i+1)*NB_KPROBES_PER_ITER]) |
| 104 | set_kprobe_tracing_state(1) |
| 105 | run_workload() |
| 106 | print('\n') |
| 107 | |
| 108 | if __name__ == "__main__": |
| 109 | main() |