Conversation
|
@weltling What's the use case for directly using ticks? Most points should be solved with the latest commit. :) I chose |
weltling
left a comment
There was a problem hiding this comment.
As it is a new stuff, some more obvious function names can be introduced. At least the "monotonic" is one of the useful keywords. Don't care much actually, but not everyone programs node :)
Also, while nanoseconds are good, some systems can deliver better, especially non POSIX. Or even, one could use the actual ticks directly, to implement a custom time measurement. On fast systems it's a quite realistic scenario, even with some overhead in PHP. For that purpose the actual low level units can be useful, or an explicit time unit argument. But yes, ns monotonic time is a good start, anyway, if no one cares about more.
There is an article about the portability, which i found useful some time ago http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking while implementing the PECL hrtime. Clear, there's no good chance to test all the systems, at least what should be ensured is - that there's a robust fallback on both compilation and run time.
Thanks.
| char buffer[64]; | ||
| int result = 0; | ||
|
|
| var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ | ||
| filters.c proc_open.c streamsfuncs.c http.c password.c \ | ||
| random.c,,, | ||
| random.c hrtime.c,,, |
There was a problem hiding this comment.
It should check for symbols and mark a fallback case, maybe falling back to gettimeofday() or anything better in the code. Specifically for POSIX - it should check for CLOCK_MONOTONIC define, as there can be variations in the implementations. I think, it's even better to check for different platforms explicitly - BSD, Solaris for sure, and maybe some other.
There was a problem hiding this comment.
As far as I know, CLOCK_MONOTONIC is available on FreeBSD, OpenBSD, Solaris, AIX, etc. There are just differences for CLOCK_MONOTONIC_RAW / CLOCK_MONOTONIC_PRECISE etc.
There was a problem hiding this comment.
At least one platform doesn't have it, as per the linked blog. Edge cases, still they should be covered them if they're known.
There was a problem hiding this comment.
Yes, HP-UX doesn't seem to support it.
There was a problem hiding this comment.
I added support for HP-UX just now. Any other edge cases we know of? I think the checks should be fine now with the conditional definition?
There was a problem hiding this comment.
Oh, i thought we'd rather exclude it in configure, but works this way, too. Except probably only a few can test it :/ There are no cases, i'd be aware of otherwise.
There was a problem hiding this comment.
That is not a so-easy subject to takle. Systems tend to be pretty different in their API for time measurement.
Also, you should have a read at http://nadeausoftware.com/articles/2012/03/c_c_tip_how_measure_cpu_time_benchmarking
There was a problem hiding this comment.
@jpauli That's talking about CPU time for benchmarking, that's not the use case I have. While benchmarking is another possible use case for hrtime(), the reason I created this PR and am interested in hrtime() is for event loops. I'm not even interested in a nanosecond resolution, it just happens to be provided. Milliseconds would be enough for my use case.
| /* {{{ */ | ||
| PHP_MINIT_FUNCTION(hrtime) | ||
| { | ||
| if (_timer_init()) { |
There was a problem hiding this comment.
For whatever reason, if the initialization has failed, the whole should fallback to something.
There was a problem hiding this comment.
Fail back to what? Depends on what we want to guarantee for this function. If we want to guarantee no jumps and monotony, we can't fallback to anything.
There was a problem hiding this comment.
If we don't want to make the timer a hard requirement we can either a) only register the function is the functionality is available or b) throw an exception if the function is called.
There was a problem hiding this comment.
My thought was falling back to getttimeofday() or alike, as it is supposed to be a rare case, and otherwise it needs one more condition check. Fine with being strict and exception, it solves the case as well.
There was a problem hiding this comment.
In that case we won't ever find the missing platforms and just think those are supported.
There was a problem hiding this comment.
@jpauli If it fails in MINIT it fails with a fatal error. It doesn't make sense to continue if the initialization already failed. The issue with a notice or warning is that you need a dummy return value and nobody will check the return value.
There was a problem hiding this comment.
I was talking about the case where we would replacing a failing init call by a gettimeofday() call. In such a case, we must return SUCCESS, and throw a Notice.
There was a problem hiding this comment.
There is no such case. If it can't use a monotonic time but compiled fine, it will result in a fatal error. It won't fall back to gettimeofday().
There was a problem hiding this comment.
Ok, I thought we were talking about a possible replacement by gtod() if failing , so we forget such an idea.
There was a problem hiding this comment.
@weltling wanted to do that. I don't want to do that, as it breaks the guarantee of monotony and might jump, while hrtime() usually doesn't do that.
ext/standard/hrtime.c
Outdated
| #elif TIMER_PLATFORM_POSIX | ||
|
|
||
| struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 }; | ||
| clock_gettime( CLOCK_MONOTONIC, &ts ); |
There was a problem hiding this comment.
Do we support Windows < XP?
There was a problem hiding this comment.
Nope, for 7.2 is also win7/2008r2 is the lowest, see UPGRADING.
There was a problem hiding this comment.
Ok fine, then we don't need any check on Windows, as it's guaranteed to always return true then.
ext/standard/hrtime.c
Outdated
| return; | ||
| } | ||
|
|
||
| // Use double to avoid integer overflows as we don't know the order of magnitude |
ext/standard/hrtime.c
Outdated
| } | ||
|
|
||
| // Use double to avoid integer overflows as we don't know the order of magnitude | ||
| RETURN_LONG((uint64_t) ((double) 1000000000 * _timer_current() / _timer_freq)); |
There was a problem hiding this comment.
On 32-bit it should be fine to return double, while on 64-bit zend_long were ok. For simplicity, it might be ok to just deal with double only.
There was a problem hiding this comment.
In that case we should use double only.
| <?php | ||
|
|
||
| $time = hrtime(); | ||
| usleep(500000); |
There was a problem hiding this comment.
Testing with any kind of sleep is not reliable, sleep might freeze the process on some system. You might be much better served checking some block execution dynamically, and comparing with another timing implementation like microtime(). Here fe what i invented for the hrtime ext http://svn.php.net/viewvc/pecl/hrtime/trunk/tests/helper.inc?view=markup . In general, it also sohuld be compared to an existing time implementation in PHP, to ensure the compatibility and correctness.
Thanks.
There was a problem hiding this comment.
I check for the difference now, is that fine?
There was a problem hiding this comment.
How might sleep freeze some systems? Adding random computations doesn't guarantee it waits at least the time we test against.
There was a problem hiding this comment.
Not systems, but process on some system. Sleep functions don't guarantee the exact time you pass, and the process needs to wake up, etc. The resolution of the sleep function is not guaranteed, a busy wait is more reliable for this purpose.
There was a problem hiding this comment.
As it measures the difference now, taking longer isn't a concern.
There was a problem hiding this comment.
I see, this thread is related to an outdated diff.
Thanks.
ext/standard/hrtime.c
Outdated
|
|
||
| uint64_t current_time = _timer_current(); | ||
|
|
||
| if (current_time == -1) { |
|
@weltling What do you think about the function name now? Should we keep Also, I think the module init conflicts with your extension now, no? |
|
@kelunik Oh, didn't check yet, so you don't return the nanoseconds anymore? Just nanoseconds might be simpler for the user space, probably. But the name imho should still be more descriptive, maybe at least Ofc, it would be nice to avoid the conflict with the hrtime ext. I was already thinking about some timer with callback implementation, still not sure when i could come to it :) The submodule could be renamed, if possible. Thanks. |
|
If we just publish one function, there is no need for a class. I would call it hrtime() , like in other languages. Also, I would give the user the choice of the return value : wether he wants seconds as a float, or nanoseconds as an integer (or float if overflow). |
|
@jpauli As others already noted, toggling return types depending on flags is bad and should be avoided. It's better to introduce other functions instead.
Having a return type not only depending on the input parameters, but also on the architecture, is a pretty bad thing to have. It makes code more prone to errors and I'd say it doesn't have any advantage single over always using one type. |
|
Yes I read the thread. My link was about the different constants, MONOTONIC vs MONOTONIC_RAW , f.e |
|
@jpauli Different use cases should probably have different functions. Event loops probably want |
|
@kelunik I was thinking a bit further as well. In the current form it doesn't look like nanoseconds everywhere, only in POSIX variant. The ticks/frequency will deliver possibly better or worse, so this can have unexpected effects for comparisons. The specification should be strict to follow - the ns precision is what is available on the most platforms currently, so ns precision should be delivered. Also, it might less error prone, if the function delivers the number of nanoseconds, this will reduce bugs with the fraction part. Or regarding the other idea about [seconds, nanoseconds] - this might work, need some evaluation. The accuracy is unlikely to be <= ns. Or what do your tests show on the implementation? With the module name - you can rename it to something like hrtime_mod. The name is not visible to outside anyway, but will help to avoid the module conflict with pecl hrtime. I'm getting some time to test this patch in the next weeks, will come back with the results yet. Thanks. |
|
@weltling According to https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx,
Which kind of bugs do you have in mind?
I didn't extensively test the accuracy yet.
Sure, maybe just |
|
@kelunik the link is exactly what i'm talking about. While POSIX explicitly delivers nanoseconds, Windows and Mac APIs deliver ticks. In practice, on fast machines and suitable HW source, it could be even picosecond resolution or better, at least on Windows. Or it could be worse than ns on slower machine or VM. From the doc, the Mac API works same way, and in general it's achievable by utilizing the corresponding registers directly like with inline ASM. Now, if the whole tick thing delivers a better resolution, and we don't explicitly bring it to nanoseconds - users don't know the exact time unit and the comparison of such values doesn't guarantee the crossplatform conformance. Say, comparing 1001ps and 1002ps would already give another comparison result than if both were truncated to ns. This hangs together with the other possible issue mentioned, by delivering a floating point value it can cause additional rounding errorr. Say, it'd deliver 1.000000001s (one second and one nanosecond) vs [1, 1] as same. IMO, this should be taken into evaluation, because there might be enough gap to compose such output. It is indeed about producing, as for the consumption the processing time might not matter much. Some cases I have in mind with this.
It'd be great to hear some more use cases, as this helps to form a better API in the end. So far, also looking at the other implementations including the node one - seems it might be acceptable to produce a more suitable output, whereby many APIs differ in the way they are used in different languages. phphrtime as module name were probably ok, it really doesn't matter much as it's internal only. Thanks. |
The time unit is fixed (either seconds or nanoseconds), the only thing that's not guaranteed is the accuracy. How do you want to solve that?
We can also make it 100% the same as
Event loops usually care about millisecond resolution, not seconds, so we have to scale the return value either way.
For performance testing with high accuracy with short durations you want But for the usual performance testing, both should probably be fine. |
Exactly, the time unit needs to be specified and followed strictly. In the current PR implementation, Mac and Windows don't deliver ns exactly. The combination ticks/frequency does not give nanoseconds back, that's what i tried to illustrate in the previous post. One simple solution that i'm doing in the hrtime, which however can be improved, ist to do Another solution is with the [seconds, nanoseconds], till 2038 it'll be still ok to deliver them as integers both so would be good for 32-bit anyway.
Yeah, in the most situations, the milliseconds is the most reliable resolution even today :) Just if we say "high resolution", it obliges somehow :) Itself, monotonic time in milliseconds has probably the most reliable APIs on any platforms.
I was more talking about the consuming part with regard to the overhead of hrtime() itself. One thing is that it has to be fast, but what we were discussing is the additional overhead to produce the output. And here, the actual accuracy might play good, because the gap can be big enough for some additional instructions to produce the desired output. Evermore it can be the case on the systems with the better time resolution and accuracy. Once hrtime() delivered, the actual performance evaluation time doesn't matter. For the POSIX part - yep, probably it could be reconsidered to use CLOCK_MONOTONIC_RAW where possible and if needed, just MONOTONIC seems fine enough, though. So as for me, for one - we need to ensure all the output is strictly nanoseconds, as by the specification. And then - to consider the output format that would fit for as much as possible generic cases. Regarding the microtime() compatibility - IMHO returning a string were not suitable for today's terms. But maybe indeed, either array [s, ns] or some kind of float, or even just one of those. Thanks. |
I don't understand, you say ticks/frequency doesn't work and then propose ticks/frequency as solution? Yes, it currently returns it in seconds (without |
|
I said, that ticks/frequency is not ns aligned, that's what i said. How is one supposed to compare values of "some fixed unit"? We are talking about the specification, which says "the function always delivers ns". Thanks. |
|
@kelunik ping, what's your plan to resolve the open questions? Thanks. |
|
@weltling Could you summarize the open questions or do I have to read through the entire thread? Can't remember the open points on top of my head right now. |
|
@kelunik Yes, please check through the notes yet. For what I care, there are at least these
Needs evaluation before and tests after the implementation. Thanks. |
What do you mean with "aligned"? Accuracy?
That's not what
I'm not sure, but I think I prefer consistency with |
Precision. That's what was discussed in the posts about - ticks/freq is arbitrary. Delivering nanoseconds means it is rounded to the exact precision, disregarding whether system would deliver worse/better.
Well, CLOCK_MONOTONIC_RAW would be suitable for any purpose, i think that's why it was mentioned earlier. For long running it might be also better, as it has no NTP shifts. But anyway, if getting better perf measurement support, while not hurting other things, why not?
That's where an evaluation were needed. Creating an array would take time of course, but if there's a gap in the accuracy, it would be fine. Would have to check on a number of real systems and vms, as even if it'd affect the actual result, it could be still acceptable. Thanks. |
|
@weltling I think we should split the function into two functions. Event loops have significantly other priorities than performance measurement. For event loops, |
|
In that case i'd suggest to leave another function for another PR, to hold the effort and impact manageable here. Could you please list, what is essentially different for event loops? Thanks. |
|
@weltling Event loops don't need the high accuracy, they just need the monotony. |
|
The man page says CLOCK_MONOTONIC_COARSE is arch dependent, probably it's not worth it if it'd lead to some compilcation of the setup stuff. CLOCK_MONOTONIC_RAW seems close to performance counter on Windows. After doing some research, there was some issues with CLOCK_MONOTONIC on older kernels, which seem to be not reproducible today. Probably in the end - we're fine with just CLOCK_MONOTONIC for the start, could rethink this later when the function is used in the real world and there is some feedback. Thanks. |
This adds hrtime() to provide access to the system's high-resolution timer.
|
@krakjoe there are two outstanding points, from what i remember. One should be fixed is about delivering the exact nanoseconds. The other one, about delivering [s, ns] was still not discussed to the end. Thanks. |
|
@weltling I don't care about delivering exact nanoseconds. If you want that, feel free to deliver a patch. I only care about millisecond resolution. I'd be fine with just mirroring |
|
@kelunik if you decide to change the spec, then it should be round to exact ms. Delivering numbers that the system just gives is unreliable as they can differ on different systems. In the end that would cause undefined behaviors and users likely having to do the rounding themselves. Same about microtime alike array - in the practical sense delivering ints can overwhelm a possible impact, because double comparison is unreliable. It's also too bad this patch was placed on hold since at least three months, as the feature freeze comes. If I even had time to work on it, the time for a proper testing is simply doesn't exist. I still can do some follow ups on this patch at some later point, if you're not interested anymore. Thanks. |
|
@weltling I don't see the issue with unreliability, could you show a code example and how it would fail due to unreliability? |
|
@kelunik see #2368 (comment) and follow up. Thanks. |
|
@weltling What really matters is the unit, and the unit is the same across all systems, because of https://msdn.microsoft.com/de-de/library/windows/desktop/ms644905(v=vs.85).aspx |
|
That's exactly the point. When you fuel your car, you use a well defined unit to measure it. Same way, if you deliver time, nanosecond is what fits best nowadays. If you perhaps took the trouble to read some further details on https://msdn.microsoft.com/de-de/library/windows/desktop/dn553408(v=vs.85).aspx#resolution__precision__accuracy__and_stability , other platforms have no much difference on that. Thanks. |
|
I read it, it doesn't make anything clearer. My code already delivers a known unit, seconds. Delivering nanoseconds always isn't possible due to 32 bit support, no? |
|
@kelunik well, then i'd urge you to investigate more and to do some practical testing. One resource i could mention yet were http://www.windowstimestamp.com/description. The theory is nice by unfortunately doesn't match the reality when it comes to platforms, hardware, virtualization and more. Anything above nanosecond either doesn't matter and/or is not reliable nowadays. Cutting off is done in microtime() as well, in regard to the other question also that stands out, about delivering [s, ns] as integer. There was similar discussions around 5.4/5.5 times, where people suggested to do strange things that wouldn't work reliably per se, you might lookup those as well. Fe if as in the doc, if on some system the tick interval 320ns, you might have hard times trying to compare twos subsequent results. If you don't cut off anything above ns, you might think a rounding error is a real result, because you want to deliver a float. Doing strange things doesn't really help for quality. That's why the ext/hrtime came to life, actually. Thanks. |
|
Again, I don't care about benchmarking nanoseconds with it. I just care about a monotonic time source. If you want to use that function for other purposes, please do the changes on top of the PR later then. |
|
Referring to this #2368 (comment) - so you see there is an unreliability? Then it's your call to not to care. Every PR has surrounding aspects, being ignorant about them doesn't help for quality, it's not about what one wants ;) The title of this PR is however "Implement hrtime()". As mentioned already #2368 (comment), I'm going to finish this properly when have time then, the most work is already done. Thanks. |
|
No, I don't. That's why I'm not going to put further work into this. You seem to know exactly what's missing. I'm totally fine renaming the PR to |
|
Closing in favor of #2976. |
I have no idea whether we need something for configure, AFAIK everything we support is either Windows, Apple or POSIX compatible.