Read thrift profile output from the specified input file, and print prettier information on the output file.
(in_file, out_file, options)
| 164 | |
| 165 | |
| 166 | def process_file(in_file, out_file, options): |
| 167 | """ |
| 168 | Read thrift profile output from the specified input file, and print |
| 169 | prettier information on the output file. |
| 170 | """ |
| 171 | # |
| 172 | # A naive approach would be to read the input line by line, |
| 173 | # and each time we come to a filename and address, pass it to addr2line |
| 174 | # and print the resulting information. Unfortunately, addr2line can be |
| 175 | # quite slow, especially with large executables. |
| 176 | # |
| 177 | # This approach is much faster. We read in all of the input, storing |
| 178 | # the addresses in each file that need to be resolved. We then call |
| 179 | # addr2line just once for each file. This is much faster than calling |
| 180 | # addr2line once per address. |
| 181 | # |
| 182 | |
| 183 | virt_call_regex = re.compile(r'^\s*T_VIRTUAL_CALL: (\d+) calls on (.*):$') |
| 184 | gen_prot_regex = re.compile( |
| 185 | r'^\s*T_GENERIC_PROTOCOL: (\d+) calls to (.*) with a (.*):$') |
| 186 | bt_regex = re.compile(r'^\s*#(\d+)\s*(.*) \[(0x[0-9A-Za-z]+)\]$') |
| 187 | |
| 188 | # Parse all of the input, and store it as Entry objects |
| 189 | entries = [] |
| 190 | current_entry = None |
| 191 | while True: |
| 192 | line = in_file.readline() |
| 193 | if not line: |
| 194 | break |
| 195 | |
| 196 | if line == '\n' or line.startswith('Thrift virtual call info:'): |
| 197 | continue |
| 198 | |
| 199 | virt_call_match = virt_call_regex.match(line) |
| 200 | if virt_call_match: |
| 201 | num_calls = int(virt_call_match.group(1)) |
| 202 | type_name = virt_call_match.group(2) |
| 203 | if options.cxxfilt: |
| 204 | # Type names reported by typeid() are internal names. |
| 205 | # By default, c++filt doesn't demangle internal type names. |
| 206 | # (Some versions of c++filt have a "-t" option to enable this. |
| 207 | # Other versions don't have this argument, but demangle type |
| 208 | # names passed as an argument, but not on stdin.) |
| 209 | # |
| 210 | # If the output is being filtered through c++filt, prepend |
| 211 | # "_Z" to the type name to make it look like an external name. |
| 212 | type_name = '_Z' + type_name |
| 213 | header = 'T_VIRTUAL_CALL: %d calls on "%s"' % \ |
| 214 | (num_calls, type_name) |
| 215 | if current_entry is not None: |
| 216 | entries.append(current_entry) |
| 217 | current_entry = Entry(header) |
| 218 | continue |
| 219 | |
| 220 | gen_prot_match = gen_prot_regex.match(line) |
| 221 | if gen_prot_match: |
| 222 | num_calls = int(gen_prot_match.group(1)) |
| 223 | type_name1 = gen_prot_match.group(2) |