| 235 | |
| 236 | |
| 237 | def deserialize_profile_results( |
| 238 | buff: bytes, time_scale: TimeScale = TimeScale.TIME_IN_NS |
| 239 | ) -> Tuple[Dict[str, List[ProfileEvent]], Dict[str, List[MemEvent]]]: |
| 240 | |
| 241 | prof_header_struct_size = struct.calcsize(PROF_HEADER_STRUCT_FMT) |
| 242 | prof_allocator_struct_size = struct.calcsize(ALLOCATOR_STRUCT_FMT) |
| 243 | prof_allocation_struct_size = struct.calcsize(ALLOCATION_STRUCT_FMT) |
| 244 | prof_result_struct_size = struct.calcsize(PROF_RESULT_STRUCT_FMT) |
| 245 | prof_blocks: OrderedDict[ |
| 246 | str, List[Tuple[List[ProfileData], List[MemAllocation]]] |
| 247 | ] = OrderedDict() |
| 248 | allocator_dict = {} |
| 249 | base_offset = 0 |
| 250 | |
| 251 | while base_offset < len(buff): |
| 252 | # Unpack the header for this profiling block from which we can figure |
| 253 | # out how many profiling entries are present in this block. |
| 254 | prof_header_args = list( |
| 255 | struct.unpack_from(PROF_HEADER_STRUCT_FMT, buff, offset=base_offset) |
| 256 | ) |
| 257 | # decode name in profiler header |
| 258 | prof_header_args[0] = prof_header_args[0].decode("utf-8").replace("\u0000", "") |
| 259 | prof_header = ProfilerHeader(*prof_header_args) |
| 260 | base_offset += prof_header_struct_size |
| 261 | |
| 262 | assert prof_header.prof_ver == ET_PROF_VER, ( |
| 263 | "Mismatch in version between profile dump" "and post-processing tool" |
| 264 | ) |
| 265 | # Get all the profiling (perf events) entries |
| 266 | prof_data = [] |
| 267 | for i in range(prof_header.prof_entries): |
| 268 | name_bytes, type, id, start_time, end_time = struct.unpack_from( |
| 269 | PROF_RESULT_STRUCT_FMT, |
| 270 | buff, |
| 271 | offset=base_offset + i * prof_result_struct_size, |
| 272 | ) |
| 273 | prof_data.append( |
| 274 | ProfileData( |
| 275 | # name_bytes is 32 bytes string, where if the real log event is less |
| 276 | # than 32 characters it'll be filled with 0 chars => trimming it |
| 277 | name_bytes.decode("utf-8").replace("\u0000", ""), |
| 278 | type, |
| 279 | id, |
| 280 | start_time, |
| 281 | end_time, |
| 282 | ) |
| 283 | ) |
| 284 | |
| 285 | # Move forward in the profiling block to start parsing memory allocation events. |
| 286 | base_offset += prof_result_struct_size * prof_header.max_prof_entries |
| 287 | |
| 288 | # Parse the allocator entries table, this table maps the allocator id to the |
| 289 | # string containing the name designated to this allocator. |
| 290 | for i in range(0, prof_header.allocator_entries): |
| 291 | allocator_name, allocator_id = struct.unpack_from( |
| 292 | ALLOCATOR_STRUCT_FMT, |
| 293 | buff, |
| 294 | offset=base_offset + i * prof_allocator_struct_size, |