aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/profile.c
diff options
context:
space:
mode:
authorNicolas Hillegeer <nicolas@hillegeer.com>2014-06-15 12:29:32 +0200
committerNicolas Hillegeer <nicolas@hillegeer.com>2014-07-16 17:12:34 +0200
commitdb7cd61f6297aab6343f7c6cd424d8987ca03a58 (patch)
tree85e06fa1cd4cf005facf4e63ecd0c98519effa2f /src/nvim/profile.c
parentf172b19f438b0bccdc1be0d82a6fe660c4bbd6e0 (diff)
downloadrneovim-db7cd61f6297aab6343f7c6cd424d8987ca03a58.tar.gz
rneovim-db7cd61f6297aab6343f7c6cd424d8987ca03a58.tar.bz2
rneovim-db7cd61f6297aab6343f7c6cd424d8987ca03a58.zip
profiling: implement on top of os_hrtime()
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/...
Diffstat (limited to 'src/nvim/profile.c')
-rw-r--r--src/nvim/profile.c184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/nvim/profile.c b/src/nvim/profile.c
new file mode 100644
index 0000000000..6a77d42205
--- /dev/null
+++ b/src/nvim/profile.c
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+#include "nvim/profile.h"
+#include "nvim/os/time.h"
+#include "nvim/func_attr.h"
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "profile.c.generated.h"
+#endif
+
+/// functions for profiling
+
+static proftime_T prof_wait_time;
+
+/// profile_start - return the current time
+///
+/// @return the current time
+proftime_T profile_start(void) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return os_hrtime();
+}
+
+/// profile_end - compute the time elapsed
+///
+/// @return the elapsed time from `tm` until now.
+proftime_T profile_end(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return os_hrtime() - tm;
+}
+
+/// profile_msg - return a string that represents the time in `tm`
+///
+/// @warning Do not modify or free this string, not multithread-safe.
+///
+/// @param tm The time to be represented
+/// @return a static string representing `tm` in the
+/// form "seconds.microseconds".
+const char *profile_msg(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ static char buf[50];
+
+ snprintf(buf, sizeof(buf), "%10.6lf", (double)tm / 1000000000.0);
+
+ return buf;
+}
+
+/// profile_setlimit - return the time `msec` into the future
+///
+/// @param msec milliseconds, the maximum number of milliseconds is
+/// (2^63 / 10^6) - 1 = 9.223372e+12.
+/// @return if msec > 0, returns the time msec past now. Otherwise returns
+/// the zero time.
+proftime_T profile_setlimit(int64_t msec) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (msec <= 0) {
+ // no limit
+ return profile_zero();
+ }
+
+ assert(msec <= (INT64_MAX / 1000000LL) - 1);
+
+ proftime_T nsec = (proftime_T) msec * 1000000ULL;
+ return os_hrtime() + nsec;
+}
+
+/// profile_passed_limit - check if current time has passed `tm`
+///
+/// @return true if the current time is past `tm`, false if not or if the
+/// timer was not set.
+bool profile_passed_limit(proftime_T tm) FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (tm == 0) {
+ // timer was not set
+ return false;
+ }
+
+ return profile_cmp(os_hrtime(), tm) < 0;
+}
+
+/// profile_zero - obtain the zero time
+///
+/// @return the zero time
+proftime_T profile_zero(void) FUNC_ATTR_CONST
+{
+ return 0;
+}
+
+/// profile_divide - divide the time `tm` by `count`.
+///
+/// @return 0 if count <= 0, otherwise tm / count
+proftime_T profile_divide(proftime_T tm, int count) FUNC_ATTR_CONST
+{
+ if (count <= 0) {
+ return profile_zero();
+ }
+
+ return (proftime_T) round((double) tm / (double) count);
+}
+
+/// profile_add - add the time `tm2` to `tm1`
+///
+/// @return `tm1` + `tm2`
+proftime_T profile_add(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
+{
+ return tm1 + tm2;
+}
+
+/// profile_sub - subtract `tm2` from `tm1`
+///
+/// @return `tm1` - `tm2`
+proftime_T profile_sub(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
+{
+ return tm1 - tm2;
+}
+
+/// profile_self - add the `self` time from the total time and the
+/// children's time
+///
+/// @return if `total` <= `children`, then self, otherwise `self` + `total` -
+/// `children`
+proftime_T profile_self(proftime_T self, proftime_T total, proftime_T children)
+ FUNC_ATTR_CONST
+{
+ // check that the result won't be negative, which can happen with
+ // recursive calls.
+ if (total <= children) {
+ return self;
+ }
+
+ // add the total time to self and subtract the children's time from self
+ return profile_sub(profile_add(self, total), children);
+}
+
+/// profile_get_wait - get the current waittime
+///
+/// @return the current waittime
+proftime_T profile_get_wait(void) FUNC_ATTR_PURE
+{
+ return prof_wait_time;
+}
+
+/// profile_set_wait - set the current waittime
+void profile_set_wait(proftime_T wait)
+{
+ prof_wait_time = wait;
+}
+
+/// profile_sub_wait - subtract the passed waittime since `tm`
+///
+/// @return `tma` - (waittime - `tm`)
+proftime_T profile_sub_wait(proftime_T tm, proftime_T tma) FUNC_ATTR_PURE
+{
+ proftime_T tm3 = profile_sub(profile_get_wait(), tm);
+ return profile_sub(tma, tm3);
+}
+
+/// profile_equal - check if `tm1` is equal to `tm2`
+///
+/// @return true if `tm1` == `tm2`
+bool profile_equal(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
+{
+ return tm1 == tm2;
+}
+
+/// sgn64 - calculates the sign of a 64-bit integer
+///
+/// @return -1, 0, or +1
+static inline int sgn64(int64_t x) FUNC_ATTR_CONST
+{
+ return (int) ((x > 0) - (x < 0));
+}
+
+/// profile_cmp - compare profiling times
+///
+/// Only guarantees correct results if both input times are not more than
+/// 150 years apart.
+///
+/// @return <0, 0 or >0 if `tm2` < `tm1`, `tm2` == `tm1` or `tm2` > `tm1`
+int profile_cmp(proftime_T tm1, proftime_T tm2) FUNC_ATTR_CONST
+{
+ return sgn64((int64_t)(tm2 - tm1));
+}