)]}'
{
  "commit": "02a472a0dbb7d21810ef2c56626eba2113e5a049",
  "tree": "8650000af772e2634db3a8ef9e0a2eeed479b1aa",
  "parents": [
    "eb07c060cd334ea2e6d9049c214153c5236d741e"
  ],
  "author": {
    "name": "Jukka Lehtosalo",
    "email": "jukka.lehtosalo@iki.fi",
    "time": "Wed Jul 16 13:43:40 2025 +0100"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Wed Jul 16 13:43:40 2025 +0100"
  },
  "message": "[mypyc] Optionally log a sampled operation trace to a file (#19457)\n\nLogging executed ops is useful for performance analysis. For example, we\ncan look for functions which perform many slow operations and try to\noptimize them. I\u0027ve already used this successfully to implement several\noptimizations. A typical optimization that this helps with is replacing\na generic Python function call operation with a native call. This has\nalso helped me identify inefficient code generated by mypyc.\n\nCompile using `MYPYC_LOG_TRACE\u003d1 mypyc ...` to enable trace logging. The\nlog will be written to `mypyc_trace.txt`. Roughly 1/1000 of ops of\ncertain kinds (e.g. primitive calls) are logged.\n\nThis can also be enabled by passing `log_trace\u003dTrue` to `mypycify`.\n\nCompared to profiling, this logging data is frequency-oriented instead\nof CPU time oriented, and it\u0027s mostly helpful for micro-optimizations.\nIt also needs some understanding of mypyc internals to be useful. It\u0027s\nnot generally possible to reconstruct call stacks from the event data\n(but we could improve this). However, there is very little noise in the\ndata and even small improvements can be visible.\n\nLogging isn\u0027t impacted by C compiler optimizations, so for a faster\niteration loop, optimizations can be disabled.\n\nIn the future this could possibly be used for profile-guided\noptimizations, but we\u0027d probably need to adjust the data collection a\nbit for this use case.\n\nThis is currently not documented and mostly intended for mypy or mypyc\nmaintainers for now. Also no tests yet, since this is not a user-evel\nfeature and it\u0027s disabled by default.\n\nRandom example of log entries from mypy self check:\n```\nmypy.typeops.TypeVarExtractor._merge:1146:call_c:CPyList_Extend\nmypy.semanal.SemanticAnalyzer.lookup::primitive_op:list_get_item_unsafe\nmypy.expandtype.ExpandTypeVisitor.visit_type_var__TypeVisitor_glue:239:call:mypy.expandtype.ExpandTypeVisitor.visit_type_var\nmypy.applytype.apply_generic_arguments:111:call_c:CPy_NoErrOccurred\nmypy.indirection.TypeIndirectionVisitor.visit_callable_type__TypeVisitor_glue:118:call:mypy.indirection.TypeIndirectionVisitor.visit_callable_type\nmypy.fastparse.ASTConverter.visit_Call::primitive_op:buf_init_item\nmypy.semanal.SemanticAnalyzer.is_func_scope::primitive_op:int_eq\nmypy.meet.is_overlapping_types:397:call:mypy.meet._is_subtype_is_overlapping_types_obj\nmypy.types.CallableType.serialize:2287:call_c:CPyList_SetItemUnsafe\nmypy.checkexpr.ExpressionChecker.check_argument_types:2576:call_c:CPyList_SetItemUnsafe\n```\n\nFor example, let\u0027s look at this line:\n```\nmypy.typeops.TypeVarExtractor._merge:1146:call_c:CPyList_Extend\n```\nIn method `TypeVarExtractor._merge`, on line 1146 of `mypy/typeops.py`,\nthe C primitive CPyList_Extend was called (corresponds to\n`list.extend`).\n\nI\u0027ll later add some documentation to the wiki or other developer docs\nand give examples of using and analyzing the data.",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "653199e0fb55831d63749d9b54106bd7ad0ab80c",
      "old_mode": 33188,
      "old_path": "mypyc/__main__.py",
      "new_id": "9b3973710efac36fbb129f5c0ff7dacc4ff5e5d0",
      "new_mode": 33188,
      "new_path": "mypyc/__main__.py"
    },
    {
      "type": "modify",
      "old_id": "ab7ba5393614b3100b45d0b860d011cdc70aa969",
      "old_mode": 33188,
      "old_path": "mypyc/build.py",
      "new_id": "8ddbf4d22a278784ca41ceb4c32ec2285a0a7f65",
      "new_mode": 33188,
      "new_path": "mypyc/build.py"
    },
    {
      "type": "modify",
      "old_id": "2a6f17cea5e2efad4f169ac195fc53146fef10f2",
      "old_mode": 33188,
      "old_path": "mypyc/codegen/emitmodule.py",
      "new_id": "7037409ff40bf761044e8a22c3a59145447be755",
      "new_mode": 33188,
      "new_path": "mypyc/codegen/emitmodule.py"
    },
    {
      "type": "modify",
      "old_id": "698e65155da4654c29f8333a33e1b43efd795c56",
      "old_mode": 33188,
      "old_path": "mypyc/lib-rt/CPy.h",
      "new_id": "e7a7f9a07626542e4bf4544cdc3ca19fccf48d57",
      "new_mode": 33188,
      "new_path": "mypyc/lib-rt/CPy.h"
    },
    {
      "type": "modify",
      "old_id": "d234138b2ff7bd43aaccf5ae935801a7aa7448aa",
      "old_mode": 33188,
      "old_path": "mypyc/lib-rt/misc_ops.c",
      "new_id": "8aa25cc11e0234d49ff6554888fb83802ca1d93f",
      "new_mode": 33188,
      "new_path": "mypyc/lib-rt/misc_ops.c"
    },
    {
      "type": "modify",
      "old_id": "51114926f6b238d645edaf63bb05e74eef3c3510",
      "old_mode": 33188,
      "old_path": "mypyc/options.py",
      "new_id": "50c76d3c0656e33b3fcff64b52e23dd3b6a5fad8",
      "new_mode": 33188,
      "new_path": "mypyc/options.py"
    },
    {
      "type": "modify",
      "old_id": "114a5f0a9823eedb5b2dc0ed1ce29c61805ae265",
      "old_mode": 33188,
      "old_path": "mypyc/primitives/misc_ops.py",
      "new_id": "e2a1aea1a8d6af02d904e022c5887e0e2028ab49",
      "new_mode": 33188,
      "new_path": "mypyc/primitives/misc_ops.py"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "5b20940c66bb647c0aa7346236248416264ebe23",
      "new_mode": 33188,
      "new_path": "mypyc/transform/log_trace.py"
    }
  ]
}
