Skip to content
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

php: Added nanosecond support for Timestamp #3972

Merged
merged 2 commits into from Jul 20, 2018

Conversation

lhecker
Copy link
Contributor

@lhecker lhecker commented Nov 29, 2017

This PR adds support for the nanoseconds field of the wellknown Timestamp type for PHP 5.6 and later.
The accuracy will be in the order of microseconds though, as that's the highest resolution PHP supports.


I hope this PR fullfills all necessary preconditions to be merged, but if it doesn't (e.g. because the Timestamp class is generated automatically), I'd be glad to help get this feature implemented whatever is necessary for that to happen. 🙂

@grpc-kokoro
Copy link

Thanks for your pull request. The automated tests will run as soon as one of the admins verifies this change is ok for us to run on our infrastructure.

1 similar comment
@grpc-kokoro
Copy link

Thanks for your pull request. The automated tests will run as soon as one of the admins verifies this change is ok for us to run on our infrastructure.

@lhecker
Copy link
Contributor Author

lhecker commented Mar 6, 2018

@TeBoring Could you please take a look at this ticket or assign it to someone? 🙂
I believe my code is correct and only fails due to regression tests – this PR is an improvement though and would thus not be compatible with previous tests.

@TeBoring
Copy link
Contributor

Could you check the c extension also works? https://github.com/google/protobuf/tree/master/php/ext/google/protobuf

@lhecker
Copy link
Contributor Author

lhecker commented Jun 27, 2018

@TeBoring You're right: The fromDateTime/toDateTime functions are actually also implemented in the native PHP extension. Didn't realize that. 😐

Can you run kokoro on this again?


I tried my best converting my PHP logic into C and also improving the existing C code a little bit (e.g. by not relying on the flaky gmtime() function, or by employing the ARRAY_SIZE macro).

But if possible someone more experienced in PHP extensions has to look over this PR as I was basically only poking around in the dark here (I really don't have any clue how to write PHP extensions).

@TeBoring
Copy link
Contributor

TeBoring commented Jul 10, 2018

If you run:

export ZEND_DONT_UNLOAD_MODULES=1
export USE_ZEND_ALLOC=0
valgrind --leak-check=yes php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php

You will get:

Warning: assert(): assert(0 == $timestamp->getNanos()) failed in /home/teboring/protobuf-timestamp/php/tests/memory_leak_test.php on line 155
==14741== 
==14741== HEAP SUMMARY:
==14741==     in use at exit: 77,591 bytes in 42 blocks
==14741==   total heap usage: 42,875 allocs, 42,833 frees, 9,228,805 bytes allocated
==14741== 
==14741== 32 bytes in 1 blocks are definitely lost in loss record 15 of 42
==14741==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14741==    by 0x7039E8: __zend_malloc (zend_alloc.c:2820)
==14741==    by 0x8FEF208: zend_string_alloc (zend_string.h:122)
==14741==    by 0x8FEF208: zend_string_init (zend_string.h:158)
==14741==    by 0x8FEF208: zim_Timestamp_fromDateTime (message.c:1289)
==14741==    by 0x7D020F: ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:970)
==14741==    by 0x77753A: execute_ex (zend_vm_execute.h:429)
==14741==    by 0x7D21AF: zend_execute (zend_vm_execute.h:474)
==14741==    by 0x72DBF2: zend_execute_scripts (zend.c:1476)
==14741==    by 0x6CA37F: php_execute_script (main.c:2537)
==14741==    by 0x7D4435: do_cli (php_cli.c:993)
==14741==    by 0x432EFB: main (php_cli.c:1381)

#endif

PHP_PROTO_ZVAL_STRING(&function_name, "date_format", 1);
PHP_PROTO_ZVAL_STRING(&format_string, "u", 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

You forget to call zval_dtor(&format_string); which causes memory leak.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

};

if (call_user_function(EG(function_table), NULL, &function_name, &retval,
ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of using ARRAY_SZIE, why not using actual number?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See my explanation for ARRAY_SIZE below. 🙂
Should I change it back?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation. ARRAY_SIZE looks good to me.

@@ -42,6 +42,10 @@
#define MAX_LENGTH_OF_INT64 20
#define SIZEOF_INT64 8

/* From Chromium. */
#define ARRAY_SIZE(x) \
((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
Copy link
Contributor

Choose a reason for hiding this comment

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

Why ARRAY_SIZE is like this? Is it related to implementation detail of php runtime?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've taken that macro from here: https://github.com/google/protobuf/blob/3beb19945b599d448c2524666effe1acdf29165f/php/ext/google/protobuf/upb.c#L8107-L8109

It's a classical macro to determine the size of constant-sized arrays in C.
For instance if you have a char foo[25] then ARRAY_SIZE(foo) will evaluate to 25.

You can find an explanation here: https://stackoverflow.com/a/4415646

Since such a macro is much safer than hardcoding the size of arrays I've started replacing these hardcoded numbers in any PHP-extension code I touched, but I'd recommend using that macro in other places as well as soon as possible. It will probably reduce accidential mistakes in future PRs. 🙂

@TeBoring
Copy link
Contributor

Warning: assert(): assert(0 == $timestamp->getNanos()) failed in /home/teboring/protobuf-timestamp/php/tests/memory_leak_test.php on line 155

You probably also need to fix the memory_leak_test.

@TeBoring
Copy link
Contributor

any update?

@lhecker
Copy link
Contributor Author

lhecker commented Jul 12, 2018

@TeBoring Sorry, I'm pretty busy at the moment and forgot about this PR for the last few days.
I "allocated" myself some time tomorrow though to fix the remaining issues in this PR. 🙂
(It'd be nice if I can get valgrind running on macOS though. 🤔)

@TeBoring
Copy link
Contributor

TeBoring commented Jul 12, 2018 via email

@lhecker
Copy link
Contributor Author

lhecker commented Jul 13, 2018

@TeBoring I fixed this one remaining issue just now. Sorry that you had to wait that long. 🙂

@TeBoring
Copy link
Contributor

For php 7.1, c extension test:

1) WellKnownTest::testTimestamp
Failed asserting that 12345000 is identical to 0.
/tmp/protobuf/protobuf/php/tests/protobuf/php/tests/well_known_test.php:315

@lhecker
Copy link
Contributor Author

lhecker commented Jul 18, 2018

@TeBoring You (or Kokoro) seem to have made a mistake when testing my PR:
You're using the new C extension (= from this branch) which correctly returns 12345000 for getNanos(), but you're using the old phpunit test (= from master branch or older) for testing.


Proof for my "accusation":
The message

Failed asserting that <actual> is identical to <expected>.

is generated by phpunit's assertSame() function.
But if you check the diff of this PR you'll notice that I replaced the assertSame() in well_known_test.php:315.
It uses assertEqual() now instead, which would print an error message like this:

Failed asserting that <actual> matches expected <expected>.

If I'm correct this means that you're trying to test the changed C extension using the old test code, which is not possible in this case.

@TeBoring
Copy link
Contributor

I doubt it's our compatibility test.
https://github.com/google/protobuf/blob/master/php/tests/compatibility_test.sh#L123
Here we have some sed script to fix compatibility test. Could you help add one to fix the broken case?

@lhecker
Copy link
Contributor Author

lhecker commented Jul 19, 2018

@TeBoring My fork was out of date and would've resulted in a merge conflict if I touch that file.
I've thus taken the liberty to rebase my fork on the current master.

I also sadly didn't quite understand your last comment.
So I went ahead and wrote a sed command, which simply removes the entire testTimestamp function from the test file.

I feel like this solution is possibly a bit like shooting sparrows with cannons, but I didn't had any better idea. Do you happen to have one?

@TeBoring
Copy link
Contributor

@lhecker Thanks for the fix. There were some incorrect test. When we update the against compatibility tests, we will have the correct test. Before that, we just manually disable them. I think your approach is acceptable, because that test is truly not correct.

@TeBoring TeBoring merged commit e7746f4 into protocolbuffers:master Jul 20, 2018
@lhecker
Copy link
Contributor Author

lhecker commented Jul 20, 2018

@TeBoring Thanks for merging this and helping me ironing out all these issues in my PR. 🙂🎉

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.

None yet

6 participants