-
Notifications
You must be signed in to change notification settings - Fork 7.9k
random: Pass algorithm and state together as php_random_algo_with_state
#13350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Since 162e1dc, the `php_random_status` struct contains just a single `void*`, resulting in needless indirection when accessing the engine state and thus decreasing readability because of the additional non-meaningful `->state` references / the local helper variables. There is also a small, but measurable performance benefit: <?php $e = new Random\Engine\Xoshiro256StarStar(0); $r = new Random\Randomizer($e); for ($i = 0; $i < 15; $i++) var_dump(strlen($r->getBytes(100000000))); goes from roughly 3.85s down to 3.60s. The names of the `status` variables have not yet been touched to keep the diff small. They will be renamed to the more appropriate `state` in a follow-up cleanup commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with void *
is that it makes things more error prone as you can add there anything by mistake. So from the API caller, it makes actually thinks more error prone. I understand why you want to make this change from the internal PoV but not sure if this is an ideal API design. Personally I try to stay away from void *
if possible and use it just as the last resort. In this case it might make sense as you want to probably make it generic but maybe having a typed wrapper around it is not that bad and might catch some mistakes.
@bukka The engine state is stored in a typedef struct _php_random_status_ {
void *state;
} php_random_status; In fact I've increased type safety where possible in previous PRs leading up to this change, e.g. in 0d18f41. As a possible follow-up, I plan to remove the typedef struct _php_random_algo {
const size_t state_size;
void (*seed)(void *status, uint64_t seed);
php_random_result (*generate)(void *status);
zend_long (*range)(void *status, zend_long min, zend_long max);
bool (*serialize)(void *status, HashTable *data);
bool (*unserialize)(void *status, HashTable *data);
} php_random_algo; |
I meant type safety from the API caller PoV. It means after this change I could pass any pointer to php_array_pick_keys instead of |
I see. Yes, making those functions generic is an explicit design goal. As you specifically mentioned The global Mersenne Twister is a constant source of problems, especially since its state is visible towards and controllable by userland. You could fit quite a few copies of the 256-bit xoshiro256** or 128-bit PcgOneseq128XslRr64 state into the 2.5 kB of global Mersenne Twister 😄 see also: #13290 (comment) |
I could imagine introducing a new struct {
const php_random_algo *algo;
void *state;
} that allows passing the algorithm and associated state as a single non-pointer parameter, but I'm not sure if this would improve type safety in a measurable way? What do you think? |
Maybe instead of void* you could create some dummy structure for the state that will be as a whole casted to the actual state by the engines. The actual struct would not be used (it could have just contain one char array element for example) but it would keep the caller type safety as the caller would have to operate with specific pointer... |
Sorry for the delay in getting back to this, was busy with other stuff. I've thought about the suggestion and made the change locally and I don't believe moving away from the My suggestion of adding the struct in #13350 (comment) on the other hand feels like a value-add to me, because it allows one to store and pass the algorithm + associated state in an atomic fashion. The struct will even be passed as a register pair, making it zero-cost from a performance perspective. |
Your suggestion is fine. I though that you want just pass state on its own and don't need algo but if its useful then cool. My suggestion was for user facing API only so it would be just partial improvement. |
php_random_status
php_random_algo_with_state
I've now updated the code. The user-facing APIs ( The function pointers within the |
@zeriyoshi Please add an explicit approval / request for change once you had time to look into this! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simple and elegant!
Sorry for late review!
Since 162e1dc, the
php_random_status
struct contains just a singlevoid*
, resulting in needless indirection when accessing the engine state and thus decreasing readability because of the additional non-meaningful->state
references / the local helper variables.There is also a small, but measurable performance benefit:
goes from roughly 3.85s down to 3.60s.
The names of the
status
variables have not yet been touched to keep the diff small. They will be renamed to the more appropriatestate
in a follow-up cleanup commit.