| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -265,53 +265,6 @@ extern int _PyStaticCode_InternStrings(PyCodeObject *co); | |||
| 265 | 265 | ||
| 266 | 266 | #ifdef Py_STATS | |
| 267 | 267 | ||
| 268 | - #define SPECIALIZATION_FAILURE_KINDS 30 | ||
| 269 | - | ||
| 270 | - typedef struct _specialization_stats { | ||
| 271 | - uint64_t success; | ||
| 272 | - uint64_t failure; | ||
| 273 | - uint64_t hit; | ||
| 274 | - uint64_t deferred; | ||
| 275 | - uint64_t miss; | ||
| 276 | - uint64_t deopt; | ||
| 277 | - uint64_t failure_kinds[SPECIALIZATION_FAILURE_KINDS]; | ||
| 278 | - } SpecializationStats; | ||
| 279 | - | ||
| 280 | - typedef struct _opcode_stats { | ||
| 281 | - SpecializationStats specialization; | ||
| 282 | - uint64_t execution_count; | ||
| 283 | - uint64_t pair_count[256]; | ||
| 284 | - } OpcodeStats; | ||
| 285 | - | ||
| 286 | - typedef struct _call_stats { | ||
| 287 | - uint64_t inlined_py_calls; | ||
| 288 | - uint64_t pyeval_calls; | ||
| 289 | - uint64_t frames_pushed; | ||
| 290 | - uint64_t frame_objects_created; | ||
| 291 | - } CallStats; | ||
| 292 | - | ||
| 293 | - typedef struct _object_stats { | ||
| 294 | - uint64_t allocations; | ||
| 295 | - uint64_t allocations512; | ||
| 296 | - uint64_t allocations4k; | ||
| 297 | - uint64_t allocations_big; | ||
| 298 | - uint64_t frees; | ||
| 299 | - uint64_t to_freelist; | ||
| 300 | - uint64_t from_freelist; | ||
| 301 | - uint64_t new_values; | ||
| 302 | - uint64_t dict_materialized_on_request; | ||
| 303 | - uint64_t dict_materialized_new_key; | ||
| 304 | - uint64_t dict_materialized_too_big; | ||
| 305 | - uint64_t dict_materialized_str_subclass; | ||
| 306 | - } ObjectStats; | ||
| 307 | - | ||
| 308 | - typedef struct _stats { | ||
| 309 | - OpcodeStats opcode_stats[256]; | ||
| 310 | - CallStats call_stats; | ||
| 311 | - ObjectStats object_stats; | ||
| 312 | - } PyStats; | ||
| 313 | - | ||
| 314 | - extern PyStats _py_stats; | ||
| 315 | 268 | ||
| 316 | 269 | #define STAT_INC(opname, name) _py_stats.opcode_stats[opname].specialization.name++ | |
| 317 | 270 | #define STAT_DEC(opname, name) _py_stats.opcode_stats[opname].specialization.name-- | |
@@ -321,8 +274,6 @@ extern PyStats _py_stats; | |||
| 321 | 274 | #define OBJECT_STAT_INC_COND(name, cond) \ | |
| 322 | 275 | do { if (cond) _py_stats.object_stats.name++; } while (0) | |
| 323 | 276 | ||
| 324 | - extern void _Py_PrintSpecializationStats(int to_file); | ||
| 325 | - | ||
| 326 | 277 | // Used by the _opcode extension which is built as a shared library | |
| 327 | 278 | PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); | |
| 328 | 279 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -34,6 +34,7 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc( | |||
| 34 | 34 | static inline void | |
| 35 | 35 | _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) | |
| 36 | 36 | { | |
| 37 | + _Py_DECREF_STAT_INC(); | ||
| 37 | 38 | #ifdef Py_REF_DEBUG | |
| 38 | 39 | _Py_RefTotal--; | |
| 39 | 40 | #endif | |
@@ -51,6 +52,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) | |||
| 51 | 52 | static inline void | |
| 52 | 53 | _Py_DECREF_NO_DEALLOC(PyObject *op) | |
| 53 | 54 | { | |
| 55 | + _Py_DECREF_STAT_INC(); | ||
| 54 | 56 | #ifdef Py_REF_DEBUG | |
| 55 | 57 | _Py_RefTotal--; | |
| 56 | 58 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -51,6 +51,8 @@ A standard interface exists for objects that contain an array of items | |||
| 51 | 51 | whose size is determined when the object is allocated. | |
| 52 | 52 | */ | |
| 53 | 53 | ||
| 54 | + #include "pystats.h" | ||
| 55 | + | ||
| 54 | 56 | /* Py_DEBUG implies Py_REF_DEBUG. */ | |
| 55 | 57 | #if defined(Py_DEBUG) && !defined(Py_REF_DEBUG) | |
| 56 | 58 | # define Py_REF_DEBUG | |
@@ -490,6 +492,7 @@ PyAPI_FUNC(void) _Py_DecRef(PyObject *); | |||
| 490 | 492 | ||
| 491 | 493 | static inline void Py_INCREF(PyObject *op) | |
| 492 | 494 | { | |
| 495 | + _Py_INCREF_STAT_INC(); | ||
| 493 | 496 | #if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000 | |
| 494 | 497 | // Stable ABI for Python 3.10 built in debug mode. | |
| 495 | 498 | _Py_IncRef(op); | |
@@ -506,7 +509,6 @@ static inline void Py_INCREF(PyObject *op) | |||
| 506 | 509 | # define Py_INCREF(op) Py_INCREF(_PyObject_CAST(op)) | |
| 507 | 510 | #endif | |
| 508 | 511 | ||
| 509 | - | ||
| 510 | 512 | #if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000 | |
| 511 | 513 | // Stable ABI for limited C API version 3.10 of Python debug build | |
| 512 | 514 | static inline void Py_DECREF(PyObject *op) { | |
@@ -517,6 +519,7 @@ static inline void Py_DECREF(PyObject *op) { | |||
| 517 | 519 | #elif defined(Py_REF_DEBUG) | |
| 518 | 520 | static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) | |
| 519 | 521 | { | |
| 522 | + _Py_DECREF_STAT_INC(); | ||
| 520 | 523 | _Py_RefTotal--; | |
| 521 | 524 | if (--op->ob_refcnt != 0) { | |
| 522 | 525 | if (op->ob_refcnt < 0) { | |
@@ -532,6 +535,7 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op) | |||
| 532 | 535 | #else | |
| 533 | 536 | static inline void Py_DECREF(PyObject *op) | |
| 534 | 537 | { | |
| 538 | + _Py_DECREF_STAT_INC(); | ||
| 535 | 539 | // Non-limited C API and limited C API for Python 3.9 and older access | |
| 536 | 540 | // directly PyObject.ob_refcnt. | |
| 537 | 541 | if (--op->ob_refcnt == 0) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,77 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + #ifndef Py_PYSTATS_H | ||
| 4 | + #define Py_PYSTATS_H | ||
| 5 | + #ifdef __cplusplus | ||
| 6 | + extern "C" { | ||
| 7 | + #endif | ||
| 8 | + | ||
| 9 | + #ifdef Py_STATS | ||
| 10 | + | ||
| 11 | + #define SPECIALIZATION_FAILURE_KINDS 32 | ||
| 12 | + | ||
| 13 | + typedef struct _specialization_stats { | ||
| 14 | + uint64_t success; | ||
| 15 | + uint64_t failure; | ||
| 16 | + uint64_t hit; | ||
| 17 | + uint64_t deferred; | ||
| 18 | + uint64_t miss; | ||
| 19 | + uint64_t deopt; | ||
| 20 | + uint64_t failure_kinds[SPECIALIZATION_FAILURE_KINDS]; | ||
| 21 | + } SpecializationStats; | ||
| 22 | + | ||
| 23 | + typedef struct _opcode_stats { | ||
| 24 | + SpecializationStats specialization; | ||
| 25 | + uint64_t execution_count; | ||
| 26 | + uint64_t pair_count[256]; | ||
| 27 | + } OpcodeStats; | ||
| 28 | + | ||
| 29 | + typedef struct _call_stats { | ||
| 30 | + uint64_t inlined_py_calls; | ||
| 31 | + uint64_t pyeval_calls; | ||
| 32 | + uint64_t frames_pushed; | ||
| 33 | + uint64_t frame_objects_created; | ||
| 34 | + } CallStats; | ||
| 35 | + | ||
| 36 | + typedef struct _object_stats { | ||
| 37 | + uint64_t increfs; | ||
| 38 | + uint64_t decrefs; | ||
| 39 | + uint64_t allocations; | ||
| 40 | + uint64_t allocations512; | ||
| 41 | + uint64_t allocations4k; | ||
| 42 | + uint64_t allocations_big; | ||
| 43 | + uint64_t frees; | ||
| 44 | + uint64_t to_freelist; | ||
| 45 | + uint64_t from_freelist; | ||
| 46 | + uint64_t new_values; | ||
| 47 | + uint64_t dict_materialized_on_request; | ||
| 48 | + uint64_t dict_materialized_new_key; | ||
| 49 | + uint64_t dict_materialized_too_big; | ||
| 50 | + uint64_t dict_materialized_str_subclass; | ||
| 51 | + } ObjectStats; | ||
| 52 | + | ||
| 53 | + typedef struct _stats { | ||
| 54 | + OpcodeStats opcode_stats[256]; | ||
| 55 | + CallStats call_stats; | ||
| 56 | + ObjectStats object_stats; | ||
| 57 | + } PyStats; | ||
| 58 | + | ||
| 59 | + PyAPI_DATA(PyStats) _py_stats; | ||
| 60 | + | ||
| 61 | + extern void _Py_PrintSpecializationStats(int to_file); | ||
| 62 | + | ||
| 63 | + | ||
| 64 | + #define _Py_INCREF_STAT_INC() _py_stats.object_stats.increfs++ | ||
| 65 | + #define _Py_DECREF_STAT_INC() _py_stats.object_stats.decrefs++ | ||
| 66 | + | ||
| 67 | + #else | ||
| 68 | + | ||
| 69 | + #define _Py_INCREF_STAT_INC() ((void)0) | ||
| 70 | + #define _Py_DECREF_STAT_INC() ((void)0) | ||
| 71 | + | ||
| 72 | + #endif // !Py_STATS | ||
| 73 | + | ||
| 74 | + #ifdef __cplusplus | ||
| 75 | + } | ||
| 76 | + #endif | ||
| 77 | + #endif /* !Py_PYSTATs_H */ | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1509,6 +1509,7 @@ PYTHON_HEADERS= \ | |||
| 1509 | 1509 | $(srcdir)/Include/pymem.h \ | |
| 1510 | 1510 | $(srcdir)/Include/pyport.h \ | |
| 1511 | 1511 | $(srcdir)/Include/pystate.h \ | |
| 1512 | + $(srcdir)/Include/pystats.h \ | ||
| 1512 | 1513 | $(srcdir)/Include/pystrcmp.h \ | |
| 1513 | 1514 | $(srcdir)/Include/pystrtod.h \ | |
| 1514 | 1515 | $(srcdir)/Include/pythonrun.h \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -280,6 +280,7 @@ | |||
| 280 | 280 | <ClInclude Include="..\Include\pymem.h" /> | |
| 281 | 281 | <ClInclude Include="..\Include\pyport.h" /> | |
| 282 | 282 | <ClInclude Include="..\Include\pystate.h" /> | |
| 283 | + <ClInclude Include="..\Include\pystats.h" /> | ||
| 283 | 284 | <ClInclude Include="..\Include\pystrcmp.h" /> | |
| 284 | 285 | <ClInclude Include="..\Include\pystrtod.h" /> | |
| 285 | 286 | <ClInclude Include="..\Include\pythonrun.h" /> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -174,6 +174,9 @@ | |||
| 174 | 174 | <ClInclude Include="..\Include\pystate.h"> | |
| 175 | 175 | <Filter>Include</Filter> | |
| 176 | 176 | </ClInclude> | |
| 177 | + <ClInclude Include="..\Include\pystats.h"> | ||
| 178 | + <Filter>Include</Filter> | ||
| 179 | + </ClInclude> | ||
| 177 | 180 | <ClInclude Include="..\Include\pystrcmp.h"> | |
| 178 | 181 | <Filter>Include</Filter> | |
| 179 | 182 | </ClInclude> | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -55,6 +55,7 @@ | |||
| 55 | 55 | #undef Py_DECREF | |
| 56 | 56 | #define Py_DECREF(arg) \ | |
| 57 | 57 | do { \ | |
| 58 | + _Py_DECREF_STAT_INC(); \ | ||
| 58 | 59 | PyObject *op = _PyObject_CAST(arg); \ | |
| 59 | 60 | if (--op->ob_refcnt == 0) { \ | |
| 60 | 61 | destructor dealloc = Py_TYPE(op)->tp_dealloc; \ | |
@@ -78,6 +79,7 @@ | |||
| 78 | 79 | #undef _Py_DECREF_SPECIALIZED | |
| 79 | 80 | #define _Py_DECREF_SPECIALIZED(arg, dealloc) \ | |
| 80 | 81 | do { \ | |
| 82 | + _Py_DECREF_STAT_INC(); \ | ||
| 81 | 83 | PyObject *op = _PyObject_CAST(arg); \ | |
| 82 | 84 | if (--op->ob_refcnt == 0) { \ | |
| 83 | 85 | destructor d = (destructor)(dealloc); \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -191,6 +191,8 @@ print_object_stats(FILE *out, ObjectStats *stats) | |||
| 191 | 191 | fprintf(out, "Object allocations over 4 kbytes: %" PRIu64 "\n", stats->allocations_big); | |
| 192 | 192 | fprintf(out, "Object frees: %" PRIu64 "\n", stats->frees); | |
| 193 | 193 | fprintf(out, "Object new values: %" PRIu64 "\n", stats->new_values); | |
| 194 | + fprintf(out, "Object increfs: %" PRIu64 "\n", stats->increfs); | ||
| 195 | + fprintf(out, "Object decrefs: %" PRIu64 "\n", stats->decrefs); | ||
| 194 | 196 | fprintf(out, "Object materialize dict (on request): %" PRIu64 "\n", stats->dict_materialized_on_request); | |
| 195 | 197 | fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); | |
| 196 | 198 | fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,6 +8,7 @@ | |||
| 8 | 8 | from datetime import date | |
| 9 | 9 | import itertools | |
| 10 | 10 | import argparse | |
| 11 | + import sys | ||
| 11 | 12 | ||
| 12 | 13 | if os.name == "nt": | |
| 13 | 14 | DEFAULT_DIR = "c:\\temp\\py_stats\\" | |
@@ -88,7 +89,11 @@ def gather_stats(): | |||
| 88 | 89 | for filename in os.listdir(DEFAULT_DIR): | |
| 89 | 90 | with open(os.path.join(DEFAULT_DIR, filename)) as fd: | |
| 90 | 91 | for line in fd: | |
| 91 | - key, value = line.split(":") | ||
| 92 | + try: | ||
| 93 | + key, value = line.split(":") | ||
| 94 | + except ValueError: | ||
| 95 | + print (f"Unparsable line: '{line.strip()}' in {filename}", file=sys.stderr) | ||
| 96 | + continue | ||
| 92 | 97 | key = key.strip() | |
| 93 | 98 | value = int(value) | |
| 94 | 99 | stats[key] += value | |
@@ -265,17 +270,20 @@ def emit_call_stats(stats): | |||
| 265 | 270 | ||
| 266 | 271 | def emit_object_stats(stats): | |
| 267 | 272 | with Section("Object stats", summary="allocations, frees and dict materializatons"): | |
| 268 | - total = stats.get("Object new values") | ||
| 273 | + total_materializations = stats.get("Object new values") | ||
| 274 | + total_allocations = stats.get("Object allocations") | ||
| 269 | 275 | rows = [] | |
| 270 | 276 | for key, value in stats.items(): | |
| 271 | 277 | if key.startswith("Object"): | |
| 272 | 278 | if "materialize" in key: | |
| 273 | - materialize = f"{100*value/total:0.1f}%" | ||
| 279 | + ratio = f"{100*value/total_materializations:0.1f}%" | ||
| 280 | + elif "allocations" in key: | ||
| 281 | + ratio = f"{100*value/total_allocations:0.1f}%" | ||
| 274 | 282 | else: | |
| 275 | - materialize = "" | ||
| 283 | + ratio = "" | ||
| 276 | 284 | label = key[6:].strip() | |
| 277 | 285 | label = label[0].upper() + label[1:] | |
| 278 | - rows.append((label, value, materialize)) | ||
| 286 | + rows.append((label, value, ratio)) | ||
| 279 | 287 | emit_table(("", "Count:", "Ratio:"), rows) | |
| 280 | 288 | ||
| 281 | 289 | def get_total(opcode_stats): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments