| 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # The MIT License (MIT) |
| 4 | # |
| 5 | # Copyright (C) 2015 - Julien Desfossez <jdesfossez@efficios.com> |
| 6 | # |
| 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy |
| 8 | # of this software and associated documentation files (the "Software"), to deal |
| 9 | # in the Software without restriction, including without limitation the rights |
| 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 11 | # copies of the Software, and to permit persons to whom the Software is |
| 12 | # furnished to do so, subject to the following conditions: |
| 13 | # |
| 14 | # The above copyright notice and this permission notice shall be included in |
| 15 | # all copies or substantial portions of the Software. |
| 16 | # |
| 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 23 | # SOFTWARE. |
| 24 | |
| 25 | import sys |
| 26 | import os |
| 27 | import stat |
| 28 | import argparse |
| 29 | |
| 30 | try: |
| 31 | from babeltrace import TraceCollection, CTFScope |
| 32 | except ImportError: |
| 33 | # quick fix for debian-based distros |
| 34 | sys.path.append("/usr/local/lib/python%d.%d/site-packages" % |
| 35 | (sys.version_info.major, sys.version_info.minor)) |
| 36 | from babeltrace import TraceCollection, CTFScope |
| 37 | |
| 38 | preambule = """#!/usr/bin/env python3 |
| 39 | |
| 40 | import sys |
| 41 | import time |
| 42 | import argparse |
| 43 | |
| 44 | NSEC_PER_SEC = 1000000000 |
| 45 | |
| 46 | try: |
| 47 | from babeltrace import TraceCollection |
| 48 | except ImportError: |
| 49 | # quick fix for debian-based distros |
| 50 | sys.path.append("/usr/local/lib/python%d.%d/site-packages" % |
| 51 | (sys.version_info.major, sys.version_info.minor)) |
| 52 | from babeltrace import TraceCollection |
| 53 | |
| 54 | |
| 55 | class TraceParser: |
| 56 | def __init__(self, trace): |
| 57 | self.trace = trace |
| 58 | self.event_count = {} |
| 59 | |
| 60 | def ns_to_hour_nsec(self, ns): |
| 61 | d = time.localtime(ns/NSEC_PER_SEC) |
| 62 | return "%02d:%02d:%02d.%09d" % (d.tm_hour, d.tm_min, d.tm_sec, |
| 63 | ns % NSEC_PER_SEC) |
| 64 | |
| 65 | def parse(self): |
| 66 | # iterate over all the events |
| 67 | for event in self.trace.events: |
| 68 | if not event.name in self.event_count.keys(): |
| 69 | self.event_count[event.name] = 0 |
| 70 | method_name = "handle_%s" % \ |
| 71 | event.name.replace(":", "_").replace("+", "_") |
| 72 | # call the function to handle each event individually |
| 73 | if hasattr(TraceParser, method_name): |
| 74 | func = getattr(TraceParser, method_name) |
| 75 | func(self, event) |
| 76 | # print statistics after parsing the trace |
| 77 | print("Total event count:") |
| 78 | for e in self.event_count.keys(): |
| 79 | print("- %s: %d" % (e, self.event_count[e])) |
| 80 | |
| 81 | """ |
| 82 | |
| 83 | end = """ |
| 84 | if __name__ == "__main__": |
| 85 | parser = argparse.ArgumentParser(description='Trace parser') |
| 86 | parser.add_argument('path', metavar="<path/to/trace>", help='Trace path') |
| 87 | args = parser.parse_args() |
| 88 | |
| 89 | traces = TraceCollection() |
| 90 | handle = traces.add_traces_recursive(args.path, "ctf") |
| 91 | if handle is None: |
| 92 | sys.exit(1) |
| 93 | |
| 94 | t = TraceParser(traces) |
| 95 | t.parse() |
| 96 | |
| 97 | for h in handle.values(): |
| 98 | traces.remove_trace(h) |
| 99 | """ |
| 100 | |
| 101 | |
| 102 | def gen_parser(handle, fd, args): |
| 103 | for h in handle.values(): |
| 104 | for event in h.events: |
| 105 | fmt_str = "[%s] %s: { cpu_id = %s }, { " |
| 106 | fmt_fields = "self.ns_to_hour_nsec(timestamp), event.name, " \ |
| 107 | "cpu_id, " |
| 108 | name = event.name.replace(":", "_").replace("+", "_") |
| 109 | fd.write(" def handle_%s(self, event):\n" % (name)) |
| 110 | fd.write(" timestamp = event.timestamp\n") |
| 111 | fd.write(" cpu_id = event[\"cpu_id\"]\n") |
| 112 | for field in event.fields: |
| 113 | if field.scope == CTFScope.EVENT_FIELDS: |
| 114 | fname = field.name |
| 115 | # some field names are reserved keywords/variables |
| 116 | if fname == "in": |
| 117 | fname = "_in" |
| 118 | if fname == "event": |
| 119 | fname = "_event" |
| 120 | fd.write(" %s = event[\"%s\"]\n" % (fname, |
| 121 | field.name)) |
| 122 | fmt_str = fmt_str + field.name + " = %s, " |
| 123 | fmt_fields = fmt_fields + "%s, " % (fname) |
| 124 | fd.write("\n self.event_count[event.name] += 1\n") |
| 125 | if not args.quiet: |
| 126 | fd.write(" print(\"%s }\" %% (%s))\n\n" % |
| 127 | (fmt_str[0:-2], fmt_fields[0:-1])) |
| 128 | |
| 129 | |
| 130 | if __name__ == "__main__": |
| 131 | parser = argparse.ArgumentParser(description='Trace parser generator') |
| 132 | parser.add_argument('path', metavar="<path/to/trace>", help='Trace path') |
| 133 | parser.add_argument('-o', '--output', type=str, |
| 134 | metavar="<output-script-name>", |
| 135 | help='Output script name') |
| 136 | parser.add_argument('-q', '--quiet', action="store_true", |
| 137 | help='Generate a quiet parser (no print)') |
| 138 | args = parser.parse_args() |
| 139 | |
| 140 | traces = TraceCollection() |
| 141 | handle = traces.add_traces_recursive(args.path, "ctf") |
| 142 | if handle is None: |
| 143 | sys.exit(1) |
| 144 | |
| 145 | if not args.output: |
| 146 | output = "generated-parser.py" |
| 147 | else: |
| 148 | output = args.output |
| 149 | |
| 150 | fd = open(output, "w") |
| 151 | fd.write(preambule) |
| 152 | gen_parser(handle, fd, args) |
| 153 | |
| 154 | for h in handle.values(): |
| 155 | traces.remove_trace(h) |
| 156 | fd.write(end) |
| 157 | fd.close() |
| 158 | os.chmod(output, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | |
| 159 | stat.S_IRGRP | stat.S_IXGRP | |
| 160 | stat.S_IROTH | stat.S_IXOTH) |
| 161 | print("A trace parser for this trace has been written in", output) |