FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GH-128939: Refactor JIT optimize structs by markshannon · Pull Request #128940 · python/cpython · GitHub

Repository navigation

GH-128939: Refactor JIT optimize structs - #128940

Merged
markshannon merged 7 commits into
python:mainfrom
faster-cpython:refactor-optimize-structs
Jan 20, 2025
Merged

markshannon merged 7 commits into
python:mainfrom
faster-cpython:refactor-optimize-structs

Conversation

markshannon commented Jan 17, 2025 •
edited
Loading

Copy link
Copy Markdown
Member

Converts the ad-hoc set of flags in _Py_UopsSymbol into a tagged union.
This:

  • Makes the code more robust. Using an enum in a switch allows the C compiler to tell us if we miss any cases
  • More extensible. New kinds can be added by adding a new tag type
  • Easier to maintain. There are no (at least much fewer) hidden assumptions in the data
  • Renames all structs starting to _Py_Uops to start with JitOpt.
  • Adds a new tuple kind to demonstrate that it can be done easily and reliably.

Copy link
Copy Markdown
Member

Can you add a test that the tuple information is actually propagated? Either through testing type guard elimination happens or something. Unless you plan to refactor the tests as well :).

Copy link
Copy Markdown
Member

Random comment: JIT is an acronym, and we use the "JIT" capitalization elsewhere. "Jit" just looks... wrong.

brandtbucher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Various thoughts and questions I had while reading through. I think this is going to be a very nice improvement, though!

Other thoughts:

  • It's probably worth adding a helper for immortality checks. Basically, check if we have an immortal constant, or a known bool type. The bool part is nice, but easy to forget.
  • Any plans to update the _Py_uop_ naming to be "JIT"-ier?

Comment on lines +225 to +231
typedef union _jit_opt_symbol {
uint8_t tag;
JitOptKnownClass cls;
JitOptKnownValue value;
JitOptKnownVersion version;
JitOptTuple tuple;
} JitOptSymbol;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Could this be:

Suggested change
typedef union _jit_opt_symbol {
uint8_t tag;
JitOptKnownClass cls;
JitOptKnownValue value;
JitOptKnownVersion version;
JitOptTuple tuple;
} JitOptSymbol;
typedef struct {
uint8_t tag;
union {
JitOptKnownClass cls;
JitOptKnownValue value;
JitOptKnownVersion version;
JitOptTuple tuple;
};
} JitOptSymbol;

Then we wouldn't need to repeat the tag in each struct.

Or does the current scheme potentially pack better?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It packs better. Because structs align according to the alignment of their members, we would end up using 8 bytes for the tag if it weren't part of each struct.

Comment on lines +203 to +207
typedef struct _jit_opt_known_class {
uint8_t tag;
uint32_t version;
PyTypeObject *type;
} JitOptKnownClass;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We could probably just get the version by doing cls.type->tp_version_tag, right? Having both here just creates opportunities for them to be stale or out-of-sync, I think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

sym->cls.type->tp_version_tag is the version tag of the value's class now. sym->version.version is the version tag it would have should execution reach this point in the code. Not quite the same thing.

brandtbucher Jan 22, 2025 •
edited
Loading

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I would imagine that a sym->cls.version that's out-of-sync with sym->cls.type->tp_version_tag should result in the bottom type, then, right? It's not possible in future code, since the cached tag is stale.

Comment thread Include/internal/pycore_optimizer.h Outdated
typedef struct _jit_opt_tuple {
uint8_t tag;
uint8_t length;
uint16_t items[6];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think we have room for 7, right?

Suggested change
uint16_t items[6];
uint16_t items[7];

Comment on lines +176 to +182
case JIT_SYM_KNOWN_VALUE_TAG:
Py_CLEAR(sym->value.value);
sym_set_bottom(ctx, sym);
return false;
case JIT_SYM_TUPLE_TAG:
sym_set_bottom(ctx, sym);
return false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

These could potentially have the same version tag, right? Looking up a method or whatever on a constant value is a normal thing to do.

Comment on lines +227 to +229
case JIT_SYM_TUPLE_TAG:
sym_set_bottom(ctx, sym);
return;

brandtbucher Jan 18, 2025 •
edited
Loading

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This also seems like it could potentially be fine (transitioning from an abstract tuple to a concrete one)... could potentially need to do something recursive for the elements, though.

Comment thread Python/optimizer_symbols.c Outdated
JitOptSymbol *
_Py_uop_sym_new_unknown(JitOptContext *ctx)
{
return sym_new(ctx);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Should this be checked for NULL and replaced with out_of_space like the others?

Comment thread Python/optimizer_symbols.c Outdated
_Py_uop_sym_tuple_getitem(JitOptContext *ctx, JitOptSymbol *sym, int item)
{

if (sym->tag != JIT_SYM_TUPLE_TAG || item < 0 || item >= sym->tuple.length) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

We can handle negative indexes pretty easily here, right?

Also, this can probably be updated to work correctly for constant tuples.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Negative indexes are errors at this level. If we add a symbolic version of this, we would handle negative indexes there.

Comment thread Python/optimizer_symbols.c Outdated
int
_Py_uop_sym_tuple_length(JitOptSymbol *sym)
{
if (sym->tag != JIT_SYM_TUPLE_TAG) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Same here, this can probably be updated to work for constants.

Comment thread Python/optimizer_symbols.c Outdated
Comment on lines +447 to +450
if (size > 6) {
res->tag = JIT_SYM_KNOWN_CLASS_TAG;
res->cls.type = &PyTuple_Type;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

There are probably cases where this can be represented as a constant value (when all items are known).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Hm, although it could get tricky because nothing owns that constant, so we have to be careful not to promote its uses to constant loads.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

A constant tuple holds no more information than a tuple of constants, so there would be no advantage.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Well, it can have more than 7 items... but sure, that probably isn't very common.

Copy link
Copy Markdown
Member Author

Random comment: JIT is an acronym, and we use the "JIT" capitalization elsewhere. "Jit" just looks... wrong.

Readability. Is JITShow "JIT show" or "JITs how"?

Copy link
Copy Markdown
Member Author

Any plans to update the Py_uop naming to be "JIT"-ier?

At some point, yes.

self.assertIn("_BINARY_OP_ADD_INT", uops)
self.assertNotIn("_GUARD_BOTH_INT", uops)
self.assertNotIn("_GUARD_NOS_INT", uops)
self.assertNotIn("_GUARD_TOS_INT", uops)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This kind of check can easily pass by accident if there's typo or bytecodes change.

Would be good to have a helper that asserts also that the thing not in is an actual uop id.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It would.
I'll do that in another PR though.

markshannon merged commit f0f7b97 into python:main Jan 20, 2025
srinivasreddy pushed a commit to srinivasreddy/cpython that referenced this pull request Jan 21, 2025

Copy link
Copy Markdown
Member

Random comment: JIT is an acronym, and we use the "JIT" capitalization elsewhere. "Jit" just looks... wrong.

Readability. Is JITShow "JIT show" or "JITs how"?

I don't know, "JIT show" seems like the pretty obvious CamelCase reading. Similar to how "GILState" is "GIL State" and not "GILs tate". Not a hill I'm willing to die on, it just looks kinda weird (like "Ast" or "Ascii" or "Gil" would).

markshannon deleted the refactor-optimize-structs branch January 31, 2025 16:57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants


Back | FazBrowse Home | New Git URL