| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent fbd9391 commit 3ead2e3
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ | |||
| 5 | 5 | from types import FrameType | |
| 6 | 6 | from typing import Any, List | |
| 7 | 7 | ||
| 8 | + from cg_trace.settings import DEBUG, FAIL_ON_UNKNOWN_BYTECODE | ||
| 8 | 9 | from cg_trace.utils import better_compare_for_dataclass | |
| 9 | 10 | ||
| 10 | 11 | LOGGER = logging.getLogger(__name__) | |
@@ -155,23 +156,26 @@ def expr_that_added_elem_to_stack( | |||
| 155 | 156 | immediately. (since correctly process the bytecode when faced with jumps is not as | |
| 156 | 157 | straight forward). | |
| 157 | 158 | """ | |
| 158 | - LOGGER.debug( | ||
| 159 | - f"find_inst_that_added_elem_to_stack start_index={start_index} stack_pos={stack_pos}" | ||
| 160 | - ) | ||
| 159 | + if DEBUG: | ||
| 160 | + LOGGER.debug( | ||
| 161 | + f"find_inst_that_added_elem_to_stack start_index={start_index} stack_pos={stack_pos}" | ||
| 162 | + ) | ||
| 161 | 163 | assert stack_pos >= 0 | |
| 162 | 164 | for inst in reversed(instructions[: start_index + 1]): | |
| 163 | 165 | # Return immediately if faced with a jump | |
| 164 | 166 | if inst.opcode in dis.hasjabs or inst.opcode in dis.hasjrel: | |
| 165 | 167 | return SomethingInvolvingScaryBytecodeJump(inst.opname) | |
| 166 | 168 | ||
| 167 | 169 | if stack_pos == 0: | |
| 168 | - LOGGER.debug(f"Found it: {inst}") | ||
| 170 | + if DEBUG: | ||
| 171 | + LOGGER.debug(f"Found it: {inst}") | ||
| 169 | 172 | found_index = instructions.index(inst) | |
| 170 | 173 | break | |
| 171 | 174 | old = stack_pos | |
| 172 | 175 | stack_pos -= dis.stack_effect(inst.opcode, inst.arg) | |
| 173 | 176 | new = stack_pos | |
| 174 | - LOGGER.debug(f"Skipping ({old} -> {new}) {inst}") | ||
| 177 | + if DEBUG: | ||
| 178 | + LOGGER.debug(f"Skipping ({old} -> {new}) {inst}") | ||
| 175 | 179 | else: | |
| 176 | 180 | raise Exception("inst_index_for_stack_diff failed") | |
| 177 | 181 | ||
@@ -181,7 +185,8 @@ def expr_that_added_elem_to_stack( | |||
| 181 | 185 | def expr_from_instruction(instructions: List[Instruction], index: int) -> BytecodeExpr: | |
| 182 | 186 | inst = instructions[index] | |
| 183 | 187 | ||
| 184 | - LOGGER.debug(f"expr_from_instruction: {inst} index={index}") | ||
| 188 | + if DEBUG: | ||
| 189 | + LOGGER.debug(f"expr_from_instruction: {inst} index={index}") | ||
| 185 | 190 | ||
| 186 | 191 | if inst.opname in ["LOAD_GLOBAL", "LOAD_FAST", "LOAD_NAME", "LOAD_DEREF"]: | |
| 187 | 192 | return BytecodeVariableName(inst.argval) | |
@@ -247,24 +252,23 @@ def expr_from_instruction(instructions: List[Instruction], index: int) -> Byteco | |||
| 247 | 252 | # - LOAD_BUILD_CLASS: Called when constructing a class. | |
| 248 | 253 | # - IMPORT_NAME: Observed to result in a call to filename='<frozen | |
| 249 | 254 | # importlib._bootstrap>', linenum=389, funcname='parent' | |
| 250 | - if inst.opname not in ["LOAD_BUILD_CLASS", "IMPORT_NAME"] + WITH_OPNAMES: | ||
| 251 | - LOGGER.warning( | ||
| 252 | - f"Don't know how to handle this type of instruction: {inst.opname}" | ||
| 253 | - ) | ||
| 254 | - # Uncomment to stop execution when encountering non-ignored unknown instruction | ||
| 255 | - # class MyBytecodeException(BaseException): | ||
| 256 | - # pass | ||
| 257 | - # | ||
| 258 | - # raise MyBytecodeException() | ||
| 255 | + if FAIL_ON_UNKNOWN_BYTECODE: | ||
| 256 | + if inst.opname not in ["LOAD_BUILD_CLASS", "IMPORT_NAME"] + WITH_OPNAMES: | ||
| 257 | + LOGGER.warning( | ||
| 258 | + f"Don't know how to handle this type of instruction: {inst.opname}" | ||
| 259 | + ) | ||
| 260 | + raise BaseException() | ||
| 261 | + | ||
| 259 | 262 | return BytecodeUnknown(inst.opname) | |
| 260 | 263 | ||
| 261 | 264 | ||
| 262 | 265 | def expr_from_frame(frame: FrameType) -> BytecodeExpr: | |
| 263 | 266 | bytecode = dis.Bytecode(frame.f_code, current_offset=frame.f_lasti) | |
| 264 | 267 | ||
| 265 | - LOGGER.debug( | ||
| 266 | - f"{frame.f_code.co_filename}:{frame.f_lineno}: bytecode: \n{bytecode.dis()}" | ||
| 267 | - ) | ||
| 268 | + if DEBUG: | ||
| 269 | + LOGGER.debug( | ||
| 270 | + f"{frame.f_code.co_filename}:{frame.f_lineno}: bytecode: \n{bytecode.dis()}" | ||
| 271 | + ) | ||
| 268 | 272 | ||
| 269 | 273 | instructions = list(iter(bytecode)) | |
| 270 | 274 | last_instruction_index = [inst.offset for inst in instructions].index(frame.f_lasti) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,6 +4,10 @@ | |||
| 4 | 4 | def parse(args): | |
| 5 | 5 | parser = argparse.ArgumentParser() | |
| 6 | 6 | ||
| 7 | + parser.add_argument( | ||
| 8 | + "--debug", action="store_true", default=False, help="Enable debug logging" | ||
| 9 | + ) | ||
| 10 | + | ||
| 7 | 11 | parser.add_argument("--xml") | |
| 8 | 12 | ||
| 9 | 13 | parser.add_argument( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,7 +6,7 @@ | |||
| 6 | 6 | from datetime import datetime | |
| 7 | 7 | from io import StringIO | |
| 8 | 8 | ||
| 9 | - from cg_trace import __version__, cmdline, tracer | ||
| 9 | + from cg_trace import __version__, cmdline, settings, tracer | ||
| 10 | 10 | from cg_trace.exporter import XMLExporter | |
| 11 | 11 | ||
| 12 | 12 | ||
@@ -31,18 +31,17 @@ def record_calls(code, globals): | |||
| 31 | 31 | return all_calls_sorted, captured_stdout, captured_stderr, exit_status | |
| 32 | 32 | ||
| 33 | 33 | ||
| 34 | - def setup_logging(): | ||
| 34 | + def setup_logging(debug): | ||
| 35 | 35 | # code we run can also set up logging, so we need to set the level directly on our | |
| 36 | 36 | # own pacakge | |
| 37 | 37 | sh = logging.StreamHandler(stream=sys.stderr) | |
| 38 | 38 | ||
| 39 | 39 | pkg_logger = logging.getLogger("cg_trace") | |
| 40 | 40 | pkg_logger.addHandler(sh) | |
| 41 | - pkg_logger.setLevel(logging.INFO) | ||
| 41 | + pkg_logger.setLevel(logging.CRITICAL if debug else logging.INFO) | ||
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | 44 | def main(args=None) -> int: | |
| 45 | - setup_logging() | ||
| 46 | 45 | ||
| 47 | 46 | # from . import bytecode_reconstructor | |
| 48 | 47 | # logging.getLogger(bytecode_reconstructor.__name__).setLevel(logging.INFO) | |
@@ -53,6 +52,9 @@ def main(args=None) -> int: | |||
| 53 | 52 | ||
| 54 | 53 | opts = cmdline.parse(args) | |
| 55 | 54 | ||
| 55 | + settings.DEBUG = opts.debug | ||
| 56 | + setup_logging(opts.debug) | ||
| 57 | + | ||
| 56 | 58 | # These details of setting up the program to be run is very much inspired by `trace` | |
| 57 | 59 | # from the standard library | |
| 58 | 60 | if opts.module: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,6 @@ | |||
| 1 | + # Whether to run the call graph tracer with debugging enabled. Turning off | ||
| 2 | + # `if DEBUG: LOGGER.debug()` code completely yielded massive performance improvements. | ||
| 3 | + DEBUG = False | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + FAIL_ON_UNKNOWN_BYTECODE = False | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,6 +6,7 @@ | |||
| 6 | 6 | from typing import Any, Optional, Tuple | |
| 7 | 7 | ||
| 8 | 8 | from cg_trace.bytecode_reconstructor import BytecodeExpr, expr_from_frame | |
| 9 | + from cg_trace.settings import DEBUG | ||
| 9 | 10 | from cg_trace.utils import better_compare_for_dataclass | |
| 10 | 11 | ||
| 11 | 12 | LOGGER = logging.getLogger(__name__) | |
@@ -233,7 +234,8 @@ def profilefunc(self, frame: FrameType, event: str, arg): | |||
| 233 | 234 | if event not in ["call", "c_call"]: | |
| 234 | 235 | return | |
| 235 | 236 | ||
| 236 | - LOGGER.debug(f"profilefunc event={event}") | ||
| 237 | + if DEBUG: | ||
| 238 | + LOGGER.debug(f"profilefunc event={event}") | ||
| 237 | 239 | if event == "call": | |
| 238 | 240 | # in call, the `frame` argument is new the frame for entering the callee | |
| 239 | 241 | assert frame.f_back is not None | |
@@ -242,10 +244,12 @@ def profilefunc(self, frame: FrameType, event: str, arg): | |||
| 242 | 244 | ||
| 243 | 245 | key = (Call.hash_key(frame.f_back), callee) | |
| 244 | 246 | if key in self.python_calls: | |
| 245 | - LOGGER.debug(f"ignoring already seen call {key[0]} --> {callee}") | ||
| 247 | + if DEBUG: | ||
| 248 | + LOGGER.debug(f"ignoring already seen call {key[0]} --> {callee}") | ||
| 246 | 249 | return | |
| 247 | 250 | ||
| 248 | - LOGGER.debug(f"callee={callee}") | ||
| 251 | + if DEBUG: | ||
| 252 | + LOGGER.debug(f"callee={callee}") | ||
| 249 | 253 | call = Call.from_frame(frame.f_back) | |
| 250 | 254 | ||
| 251 | 255 | self.python_calls[key] = (call, callee) | |
@@ -258,12 +262,15 @@ def profilefunc(self, frame: FrameType, event: str, arg): | |||
| 258 | 262 | ||
| 259 | 263 | key = (Call.hash_key(frame), callee) | |
| 260 | 264 | if key in self.external_calls: | |
| 261 | - LOGGER.debug(f"ignoring already seen call {key[0]} --> {callee}") | ||
| 265 | + if DEBUG: | ||
| 266 | + LOGGER.debug(f"ignoring already seen call {key[0]} --> {callee}") | ||
| 262 | 267 | return | |
| 263 | 268 | ||
| 264 | - LOGGER.debug(f"callee={callee}") | ||
| 269 | + if DEBUG: | ||
| 270 | + LOGGER.debug(f"callee={callee}") | ||
| 265 | 271 | call = Call.from_frame(frame) | |
| 266 | 272 | ||
| 267 | 273 | self.external_calls[key] = (call, callee) | |
| 268 | 274 | ||
| 269 | - LOGGER.debug(f"{call} --> {callee}") | ||
| 275 | + if DEBUG: | ||
| 276 | + LOGGER.debug(f"{call} --> {callee}") | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments