| 757 | |
| 758 | |
| 759 | class FastgrindQueryEngine: |
| 760 | def __init__(self, reader: FastgrindBinaryReader): |
| 761 | self.reader = reader |
| 762 | self._all_thread_ids = [entry.thread_id for entry in reader.thread_table] |
| 763 | |
| 764 | def meta(self) -> dict[str, Any]: |
| 765 | meta = self.reader.meta() |
| 766 | total_malloc = sum(thread.total_malloc_bytes for thread in self.reader.thread_table) |
| 767 | total_free = sum(thread.total_free_bytes for thread in self.reader.thread_table) |
| 768 | meta.update( |
| 769 | { |
| 770 | "total_malloc_bytes": total_malloc, |
| 771 | "total_free_bytes": total_free, |
| 772 | "total_net_bytes": total_malloc - total_free, |
| 773 | } |
| 774 | ) |
| 775 | return meta |
| 776 | |
| 777 | def default_window(self) -> tuple[int, int]: |
| 778 | return self.reader.default_start_tick(), self.reader.max_tick_ms |
| 779 | |
| 780 | def list_threads(self) -> list[dict[str, Any]]: |
| 781 | return [ |
| 782 | { |
| 783 | "thread_id": thread.thread_id, |
| 784 | "first_tick_ms": thread.first_tick_ms, |
| 785 | "last_tick_ms": thread.last_tick_ms, |
| 786 | "total_malloc_bytes": thread.total_malloc_bytes, |
| 787 | "total_free_bytes": thread.total_free_bytes, |
| 788 | "net_bytes": thread.total_malloc_bytes - thread.total_free_bytes, |
| 789 | } |
| 790 | for thread in self.reader.thread_table |
| 791 | ] |
| 792 | |
| 793 | def list_functions( |
| 794 | self, |
| 795 | thread_ids: Sequence[int] | None = None, |
| 796 | query: str = "", |
| 797 | limit: int | None = 200, |
| 798 | sort: str = "alpha", |
| 799 | start_ms: int | None = None, |
| 800 | end_ms: int | None = None, |
| 801 | ) -> list[dict[str, Any]]: |
| 802 | if thread_ids: |
| 803 | available: set[int] = set() |
| 804 | for thread_id in thread_ids: |
| 805 | available.update(self.reader.thread_function_directory.get(thread_id, [])) |
| 806 | else: |
| 807 | available = set(range(1, len(self.reader.function_names))) |
| 808 | |
| 809 | query_lower = query.casefold().strip() |
| 810 | items = [] |
| 811 | for function_id in sorted(available): |
| 812 | canonical = self.reader.function_names[function_id] or "" |
| 813 | display = self.reader.display_names[function_id] or canonical |
| 814 | if query_lower and query_lower not in canonical.casefold() and query_lower not in display.casefold(): |
| 815 | continue |
| 816 | items.append( |