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
[RDY] viml: impl profiling on top of uv_hrtime() #839
Conversation
/// exactly 2 items | ||
/// @param[out] tm The proftime_T representation of `arg` | ||
/// @return OK In case of success, FAIL in case of error | ||
static int list2proftime(typval_T *arg, proftime_T *tm) |
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.
I think you need FUNC_ATTR_NONNULL_ALL here because you are not checking for arg and tm being NULL anywhere. Same for f_reltime
and f_reltimestr
(actually in my opinion every second function needs FUNC_ATTR_NONNULL_ALL
something like every fourth FUNC_ATTR_WARN_UNUSED_RESULT
). But these are static ones so such change does not contribute much.
I don't think it's a good idea to introduce changes to the other functions in this PR, but I can (and will) change the functions I modified in this PR. At first I thought that what you suggested was strange since obviously vim will never pass NULL values to any |
@@ -792,15 +783,11 @@ char * profile_msg(proftime_T *tm) | |||
*/ | |||
void profile_setlimit(long msec, proftime_T *tm) |
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.
I think it is good idea to get rid of long
here: it is guaranteed to have only 32 bits, while we need 64. If it is 32 bit than msec * 1000000L
will overflow if you set timeout in search()
to slightly more then 2 seconds.
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.
It will be 32-bit on windows indeed. But I wouldn't change the prototype of the function just yet (a bit more invasive since it's called with long
globals and whatnot). How about this:
*tm = uv_hrtime() + ((proftime_T) msec * 1000000ULL);
That should (I think) make it not overflow unless for extremely high values.
FUNC_ATTR_NONNULL_ALL should not suppress any false positives, it should make analyzer check that argument cannot be NULL. FUNC_ATTR_NONNULL_RETURN is what should suppress false positives, though you do not need this anywhere in this PR. |
Neither is particularly useful for static functions (analyzer can simply enter these functions and find out that NULL pointer is dereferenced inside or that function cannot return NULL because it uses malloc function with NONNULL_RETURN), but analyzer does not enter functions in other files (at least it was not last time I checked) so all non-static functions should have any applicable attribute. |
@ZyX-I I incorporated my version of the msec overflow you pointed out in I still believe we don't need to check for overflow though, as unsigned overflow is defined and relative intervals are not affected by overflow (unless the interval spans more than the maximum width of the type, which is unlikely). |
You mean remove But I also I think we should have a |
@@ -12242,7 +12266,7 @@ static void f_round(typval_T *argvars, typval_T *rettv) | |||
|
|||
rettv->v_type = VAR_FLOAT; | |||
if (get_float_arg(argvars, &f) == OK) | |||
rettv->vval.v_float = vim_round(f); | |||
rettv->vval.v_float = round(f); |
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.
Just mentioned: should not the removal of vim_round
be the other pull request? I cannot say I am perfect in this matter, but removing vim_round
seems completely irrelevant.
LGTM now, except for I also think @justinmk complaint is fair, but I cannot say I was thinking using |
I'll pick off the vim_round commit then, and hopefully won't forget it for another PR ;). |
@ZyX-I @justinmk I've put @ZyX-I I've also added some code which I believe guards better against overflow:
Let me know what you think. @justinmk you provided some profile output earlier. I think it might be a good idea to compare the before-and-after effects of these commits. Can you post a little snippet (or try it out yourself, whatever suits), to make sure I didn't make any mistakes in that department. |
{ enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) }; } | ||
#endif | ||
#endif | ||
|
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.
macros.h
, misc.h
, structs.h
... are really bad file names as they become huge and confusing. Please create an assert.h
(or something like it) to place the ASSERT_*
macros in it from the beginning.
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.
Sure.
@philix since you were the only one that has commented on the new changes and the |
By the way, I just did two profiling runs, one on vanilla vim installed by homebrew (7.4.273), and one on this branch (which should be using The format looks good enough so at least I didn't mess that up. If someone wants to check if the numbers add up (literally), feel free :). UDPDATE: there are some (expected) differences though: :echom reltimestr(reltime()) . ' - ' . reltimestr(reltime())
" vim: 1402915103.140406 - 1402915103.140426
" nvim: 1406625.804966 - 1406625.804986 As expected, regular vim returns the seconds (and microseconds) since the UNIX epoch, and neovim... something different. What I find strange is that the first 3 digits indicate that there is some sort of relationship between the two. |
@aktau AFAIR last time I tested Vim help says that it returns “the current time”, but unlike vim help for |
Which system did you test this on? Because on OSX it's actually something "close to" nanoseconds since the UNIX epoch. Anyway, from inspecting the source it's going to be quite different for every system. I checked getting pure So, nothing to worry about I guess, unless someone is relying on On Windows, the behaviour should be the same on this branch as it is on vanilla vim (QueryPerformanceCounter). |
Let's just note it on the wiki: https://github.com/neovim/neovim/wiki/Differences-from-vim As long as we keep track of these differences it's very manageable to check the "list of differences" in the unlikely event that someone reports a bug regarding this. |
There is . You see: |
Indeed, as one would expect from looking at the vanilla vim code, it's the low and high DWORD of the
Agreed. Do my overflow countermeasures look sufficient to you guys? |
@@ -0,0 +1,78 @@ | |||
#ifndef NVIM_ASSERT_H | |||
#define NVIM_ASSERT_H |
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.
👍
Shouldn't the include for sys/time.h be removed from os/time.c - or at least guarded with HAVE_SYS_TIME_H? At least in Linux it seems the include can be removed. |
@equalsraf in time it has to either be removed or That's something for another PR, but what do you guys think of this |
@aktau I'm wondering if we can stop using gettimeofday entirely. Currently gettimeofday is used in the following locations
Assuming the first two can use os_hrtime() instead and the third can be removed. The fourth case can be replaced by time() since it only uses second precision anyway. |
@equalsraf, indeed. Anywhere there is a time interval measurement, we can use a difference between About the
That one is for @philix. What you say makes sense though. |
How do you guys feel about perhaps extracting the functions to |
@aktau It makes sense. I cannot pretend I know why things contained in |
Will be properly solved by PR neovim#839. If that's merged, this commit can be removed.
Will be properly solved by PR neovim#839. If that's merged, this commit can be removed.
Will be properly solved by PR neovim#839. If that's merged, this commit can be removed.
ping, it seems this needs to be rebased |
Rebased and unit tests added. (though I really shouldn't be the one to write all these unit tests, since I implemented them I'm the one most likely to do the tests wrong). But a little sanity checking never hurt anybody. |
@Hinidu it seems |
Ugh, it appears |
@tarruda the python client is failing again: https://travis-ci.org/neovim/neovim/jobs/30018551 edit: damn, I didn't know that retriggering the build would erase the log. |
@@ -22,6 +22,15 @@ void time_init(void) | |||
uv_cond_init(&delay_cond); | |||
} | |||
|
|||
/// Obtain a high-resolution timer value |
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.
should this be "time" instead of "timer"?
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.
Both sound decent enough to me, timer
value implies a little bit more that it can't be used as an actual time, to me. (more like a relative time from an earlier call). What do you think?
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.
"timer" to me implies a timer object with a callback. Just checking if it was intentional.
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.
"timer" standalone sounds the same to me, but "timer value" sounds like something that comes out of a timer, and implies "relativity" to me. That's why I chose it. But it makes no big difference to me, to be honest.
Whew, it finally passed. I propose that this get merged so @equalsraf can take it out of his patchset. |
I'll look at this tonight, but I hope at least one other person can look at it. |
It seems @ZyX-I, @philix and @equalsraf already looked at early versions of this patch (before the squash and extraction to |
@oni-link pushed some fixes. If you approve of them I'll squash them in. |
@aktau, fixes LGTM. |
Can be quite handy, attempt to provide fallbacks for compilers that don't support _Static_assert (which is technically a C11 feature). Suppress warnings as best we can (Clang and GCC warn that we're using a C11 feature while in C99 mode). Needs to be tested for MSVC still.
Just an alias to uv_hrtime. Provides a high-resolution timer.
Should be better than gettimeofday() since libuv uses higher resolution clocks on most UNIX platforms. Libuv also tries to use monotonic clocks, kernel bugs notwithstanding, which is another win over gettimeofday(). Necessary for Windows, which doesn't have gettimeofday(). In vanilla vim, Windows uses QueryPerformanceCounter, which is the correct primitive for this sort of things, but that was removed when slimming up the codebase. Libuv uses QueryPerformanceCounter to implement uv_hrtime() on Windows so the behaviour of vim profiling on Windows should now be the same. The behaviour on Linux should be different (better) though, libuv uses more accurate primitives than gettimeofday(). Other misc. changes: - Added function attributes where relevant (const, pure, ...) - Convert functions to receive scalars: Now that proftime_T is always a (uint64_t) scalar (and not a struct), it's clearer to convert the functions to receive it as such instead of a pointer to a scalar. - Extract profiling funcs to profile.c: make everything clearer and reduces the size of the "catch-all" ex_cmds2.c - Add profile.{c,h} to clint and -Wconv: - Don't use sprintf, use snprintf - Don't use long, use int16_t/int32_t/...
It wasn't used anywhere else, our coding guidelines mandate the tightest scope possible.
Some functions are missing: - profile_self - profile_get_wait - profile_set_wait - profile_sub_wait
Great. I squashed and pushed again. Travis says it's OK too. |
viml: impl profiling on top of uv_hrtime()
} | ||
|
||
// in f_reltime() we split up the 64-bit proftime_T into two 32-bit | ||
// values, now we combine them again. |
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.
looks like this was done explicitly on line 11671, not in f_reltime()
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.
I'm sorry, I don't understand what you mean... f_reltime
splits the uint64_t
in two parts and returns it to the vimscript, this is then passed to list2proftime
by the vimscripter.
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.
Oh, I didn't follow that. Thanks.
- Include winsock2.h BEFORE windows.h (based on a comment in winsock2.h) - windows.h already provides a macro RGB(), #undef it before its redefined in macros.h - Define workaround for LC_MESSAGES until libintl can be used - MSVC define for __func__ (available in the latest update of VS2015) - SPECIAL_WILDCHAR is left undefined , it is not needed in Windows
Should be better than gettimeofday() since libuv uses higher resolution
clocks on most UNIX platforms. Libuv also tries to use monotonic clocks,
kernel bugs notwithstanding.
Necessary for Windows, which doesn't have gettimeofday().
Relevant issue: #831
References for
STATIC_ASSERT
:UPDATE: Since we now have a platform abstract
uint64_t
type (proftime_T
) instead ofLARGE_INTEGER
andstruct timeval
, I'm thinking of passing by value and perhaps even eliminating some of the one-line functions.Ping: @justinmk @ZyX-I @equalsraf