diff options
| author | Justin M. Keyes <justinkz@gmail.com> | 2014-07-16 12:46:07 -0400 | 
|---|---|---|
| committer | Justin M. Keyes <justinkz@gmail.com> | 2014-07-16 12:46:07 -0400 | 
| commit | 0412c17a6566a3cc5d324773abcf6e8a1ad40bc6 (patch) | |
| tree | 1b8beaf1d24f394efd0b6e0322d1efbb8515cf6f /src/nvim/eval.c | |
| parent | e1075ffff94fe0ddc9eb90980ad798e68c090fc6 (diff) | |
| parent | 6d0f9417ec2e9dec9666fa9c7a9b5b890f25d36a (diff) | |
| download | rneovim-0412c17a6566a3cc5d324773abcf6e8a1ad40bc6.tar.gz rneovim-0412c17a6566a3cc5d324773abcf6e8a1ad40bc6.tar.bz2 rneovim-0412c17a6566a3cc5d324773abcf6e8a1ad40bc6.zip | |
Merge pull request #839 from aktau/platform-abstract-time-fn
viml: impl profiling on top of uv_hrtime()
Diffstat (limited to 'src/nvim/eval.c')
| -rw-r--r-- | src/nvim/eval.c | 195 | 
1 files changed, 119 insertions, 76 deletions
| diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3459b5c4a0..d82f71b836 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -18,6 +18,7 @@  #include <stdbool.h>  #include <math.h> +#include "nvim/assert.h"  #include "nvim/vim.h"  #include "nvim/ascii.h"  #ifdef HAVE_LOCALE_H @@ -59,6 +60,7 @@  #include "nvim/os_unix.h"  #include "nvim/path.h"  #include "nvim/popupmnu.h" +#include "nvim/profile.h"  #include "nvim/quickfix.h"  #include "nvim/regexp.h"  #include "nvim/screen.h" @@ -1209,8 +1211,10 @@ void prof_child_enter(proftime_T *tm /* place to store waittime */  {    funccall_T *fc = current_funccal; -  if (fc != NULL && fc->func->uf_profiling) -    profile_start(&fc->prof_child); +  if (fc != NULL && fc->func->uf_profiling) { +    fc->prof_child = profile_start(); +  } +    script_prof_save(tm);  } @@ -1224,10 +1228,13 @@ void prof_child_exit(proftime_T *tm /* where waittime was stored */    funccall_T *fc = current_funccal;    if (fc != NULL && fc->func->uf_profiling) { -    profile_end(&fc->prof_child); -    profile_sub_wait(tm, &fc->prof_child);     /* don't count waiting time */ -    profile_add(&fc->func->uf_tm_children, &fc->prof_child); -    profile_add(&fc->func->uf_tml_children, &fc->prof_child); +    fc->prof_child = profile_end(fc->prof_child); +    // don't count waiting time +    fc->prof_child = profile_sub_wait(*tm, fc->prof_child); +    fc->func->uf_tm_children = +      profile_add(fc->func->uf_tm_children, fc->prof_child); +    fc->func->uf_tml_children = +      profile_add(fc->func->uf_tml_children, fc->prof_child);    }    script_prof_restore(tm);  } @@ -11646,66 +11653,101 @@ static void f_readfile(typval_T *argvars, typval_T *rettv)  } -/* - * Convert a List to proftime_T. - * Return FAIL when there is something wrong. - */ -static int list2proftime(typval_T *arg, proftime_T *tm) +/// list2proftime - convert a List to proftime_T +/// +/// @param arg The input list, must be of type VAR_LIST and have +///            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) FUNC_ATTR_NONNULL_ALL  { -  long n1, n2; -  int error = FALSE; +  if (arg->v_type != VAR_LIST +      || arg->vval.v_list == NULL +      || arg->vval.v_list->lv_len != 2) { +    return FAIL; +  } -  if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL -      || arg->vval.v_list->lv_len != 2) +  int error = false; +  varnumber_T n1 = list_find_nr(arg->vval.v_list, 0L, &error); +  varnumber_T n2 = list_find_nr(arg->vval.v_list, 1L, &error); +  if (error) {      return FAIL; -  n1 = list_find_nr(arg->vval.v_list, 0L, &error); -  n2 = list_find_nr(arg->vval.v_list, 1L, &error); -  tm->tv_sec = n1; -  tm->tv_usec = n2; -  return error ? FAIL : OK; +  } + +  // in f_reltime() we split up the 64-bit proftime_T into two 32-bit +  // values, now we combine them again. +  union { +    struct { varnumber_T low, high; } split; +    proftime_T prof; +  } u = { .split.high = n1, .split.low = n2 }; + +  *tm = u.prof; + +  return OK;  } -/* - * "reltime()" function - */ -static void f_reltime(typval_T *argvars, typval_T *rettv) +/// f_reltime - return an item that represents a time value +/// +/// @param[out] rettv Without an argument it returns the current time. With +///             one argument it returns the time passed since the argument. +///             With two arguments it returns the time passed between +///             the two arguments. +static void f_reltime(typval_T *argvars, typval_T *rettv) FUNC_ATTR_NONNULL_ALL  {    proftime_T res;    proftime_T start;    if (argvars[0].v_type == VAR_UNKNOWN) { -    /* No arguments: get current time. */ -    profile_start(&res); +    // no arguments: get current time. +    res = profile_start();    } else if (argvars[1].v_type == VAR_UNKNOWN) { -    if (list2proftime(&argvars[0], &res) == FAIL) +    if (list2proftime(&argvars[0], &res) == FAIL) {        return; -    profile_end(&res); +    } +    res = profile_end(res);    } else { -    /* Two arguments: compute the difference. */ +    // two arguments: compute the difference.      if (list2proftime(&argvars[0], &start) == FAIL -        || list2proftime(&argvars[1], &res) == FAIL) +        || list2proftime(&argvars[1], &res) == FAIL) {        return; -    profile_sub(&res, &start); +    } +    res = profile_sub(res, start);    } +  // we have to store the 64-bit proftime_T inside of a list of int's +  // (varnumber_T is defined as int). For all our supported platforms, int's +  // are at least 32-bits wide. So we'll use two 32-bit values to store it. +  union { +    struct { varnumber_T low, high; } split; +    proftime_T prof; +  } u = { .prof = res }; + +  // statically assert that the union type conv will provide the correct +  // results, if varnumber_T or proftime_T change, the union cast will need +  // to be revised. +  STATIC_ASSERT(sizeof(u.prof) == sizeof(u) && sizeof(u.split) == sizeof(u), +      "type punning will produce incorrect results on this platform"); +    rettv_list_alloc(rettv); -  long n1 = res.tv_sec; -  long n2 = res.tv_usec; -  list_append_number(rettv->vval.v_list, (varnumber_T)n1); -  list_append_number(rettv->vval.v_list, (varnumber_T)n2); +  list_append_number(rettv->vval.v_list, u.split.high); +  list_append_number(rettv->vval.v_list, u.split.low);  } -/* - * "reltimestr()" function - */ +/// f_reltimestr - return a string that represents the value of {time} +/// +/// @return The string representation of the argument, the format is the +///         number of seconds followed by a dot, followed by the number +///         of microseconds.  static void f_reltimestr(typval_T *argvars, typval_T *rettv) +  FUNC_ATTR_NONNULL_ALL  {    proftime_T tm;    rettv->v_type = VAR_STRING;    rettv->vval.v_string = NULL; -  if (list2proftime(&argvars[0], &tm) == OK) -    rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm)); +  if (list2proftime(&argvars[0], &tm) == OK) { +    rettv->vval.v_string = (char_u *) xstrdup(profile_msg(tm)); +  }  }  /* @@ -12134,7 +12176,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)    }    /* Set the time limit, if there is one. */ -  profile_setlimit(time_limit, &tm); +  tm = profile_setlimit(time_limit);    /*     * This function does not accept SP_REPEAT and SP_RETCOUNT flags. @@ -12426,7 +12468,7 @@ do_searchpair (    p_cpo = empty_option;    /* Set the time limit, if there is one. */ -  profile_setlimit(time_limit, &tm); +  tm = profile_setlimit(time_limit);    /* Make two search patterns: start/end (pat2, for in nested pairs) and     * start/middle/end (pat3, for the top pair). */ @@ -17435,8 +17477,8 @@ static void func_do_profile(ufunc_T *fp)    if (len == 0)      len = 1;      /* avoid getting error for allocating zero bytes */    fp->uf_tm_count = 0; -  profile_zero(&fp->uf_tm_self); -  profile_zero(&fp->uf_tm_total); +  fp->uf_tm_self = profile_zero(); +  fp->uf_tm_total = profile_zero();    if (fp->uf_tml_count == NULL) {      fp->uf_tml_count = xcalloc(len, sizeof(int)); @@ -17488,8 +17530,8 @@ void func_dump_profile(FILE *fd)            fprintf(fd, "Called 1 time\n");          else            fprintf(fd, "Called %d times\n", fp->uf_tm_count); -        fprintf(fd, "Total time: %s\n", profile_msg(&fp->uf_tm_total)); -        fprintf(fd, " Self time: %s\n", profile_msg(&fp->uf_tm_self)); +        fprintf(fd, "Total time: %s\n", profile_msg(fp->uf_tm_total)); +        fprintf(fd, " Self time: %s\n", profile_msg(fp->uf_tm_self));          fprintf(fd, "\n");          fprintf(fd, "count  total (s)   self (s)\n"); @@ -17556,14 +17598,14 @@ static void prof_func_line(  {    if (count > 0) {      fprintf(fd, "%5d ", count); -    if (prefer_self && profile_equal(total, self)) +    if (prefer_self && profile_equal(*total, *self))        fprintf(fd, "           ");      else -      fprintf(fd, "%s ", profile_msg(total)); -    if (!prefer_self && profile_equal(total, self)) +      fprintf(fd, "%s ", profile_msg(*total)); +    if (!prefer_self && profile_equal(*total, *self))        fprintf(fd, "           ");      else -      fprintf(fd, "%s ", profile_msg(self)); +      fprintf(fd, "%s ", profile_msg(*self));    } else      fprintf(fd, "                            ");  } @@ -17573,11 +17615,9 @@ static void prof_func_line(   */  static int prof_total_cmp(const void *s1, const void *s2)  { -  ufunc_T     *p1, *p2; - -  p1 = *(ufunc_T **)s1; -  p2 = *(ufunc_T **)s2; -  return profile_cmp(&p1->uf_tm_total, &p2->uf_tm_total); +  ufunc_T *p1 = *(ufunc_T **)s1; +  ufunc_T *p2 = *(ufunc_T **)s2; +  return profile_cmp(p1->uf_tm_total, p2->uf_tm_total);  }  /* @@ -17585,11 +17625,9 @@ static int prof_total_cmp(const void *s1, const void *s2)   */  static int prof_self_cmp(const void *s1, const void *s2)  { -  ufunc_T     *p1, *p2; - -  p1 = *(ufunc_T **)s1; -  p2 = *(ufunc_T **)s2; -  return profile_cmp(&p1->uf_tm_self, &p2->uf_tm_self); +  ufunc_T *p1 = *(ufunc_T **)s1; +  ufunc_T *p2 = *(ufunc_T **)s2; +  return profile_cmp(p1->uf_tm_self, p2->uf_tm_self);  } @@ -18018,8 +18056,8 @@ call_user_func (      if (fp->uf_profiling          || (fc->caller != NULL && fc->caller->func->uf_profiling)) {        ++fp->uf_tm_count; -      profile_start(&call_start); -      profile_zero(&fp->uf_tm_children); +      call_start = profile_start(); +      fp->uf_tm_children = profile_zero();      }      script_prof_save(&wait_start);    } @@ -18046,13 +18084,16 @@ call_user_func (    if (do_profiling == PROF_YES && (fp->uf_profiling                                     || (fc->caller != NULL &&                                         fc->caller->func->uf_profiling))) { -    profile_end(&call_start); -    profile_sub_wait(&wait_start, &call_start); -    profile_add(&fp->uf_tm_total, &call_start); -    profile_self(&fp->uf_tm_self, &call_start, &fp->uf_tm_children); +    call_start = profile_end(call_start); +    call_start = profile_sub_wait(wait_start, call_start); +    fp->uf_tm_total = profile_add(fp->uf_tm_total, call_start); +    fp->uf_tm_self = profile_self(fp->uf_tm_self, call_start, +        fp->uf_tm_children);      if (fc->caller != NULL && fc->caller->func->uf_profiling) { -      profile_add(&fc->caller->func->uf_tm_children, &call_start); -      profile_add(&fc->caller->func->uf_tml_children, &call_start); +      fc->caller->func->uf_tm_children = +        profile_add(fc->caller->func->uf_tm_children, call_start); +      fc->caller->func->uf_tml_children = +        profile_add(fc->caller->func->uf_tml_children, call_start);      }    } @@ -18415,9 +18456,9 @@ void func_line_start(void *cookie)      while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)        --fp->uf_tml_idx;      fp->uf_tml_execed = FALSE; -    profile_start(&fp->uf_tml_start); -    profile_zero(&fp->uf_tml_children); -    profile_get_wait(&fp->uf_tml_wait); +    fp->uf_tml_start = profile_start(); +    fp->uf_tml_children = profile_zero(); +    fp->uf_tml_wait = profile_get_wait();    }  } @@ -18444,11 +18485,13 @@ void func_line_end(void *cookie)    if (fp->uf_profiling && fp->uf_tml_idx >= 0) {      if (fp->uf_tml_execed) {        ++fp->uf_tml_count[fp->uf_tml_idx]; -      profile_end(&fp->uf_tml_start); -      profile_sub_wait(&fp->uf_tml_wait, &fp->uf_tml_start); -      profile_add(&fp->uf_tml_total[fp->uf_tml_idx], &fp->uf_tml_start); -      profile_self(&fp->uf_tml_self[fp->uf_tml_idx], &fp->uf_tml_start, -          &fp->uf_tml_children); +      fp->uf_tml_start = profile_end(fp->uf_tml_start); +      fp->uf_tml_start = profile_sub_wait(fp->uf_tml_wait, fp->uf_tml_start); +      fp->uf_tml_total[fp->uf_tml_idx] = +        profile_add(fp->uf_tml_total[fp->uf_tml_idx], fp->uf_tml_start); +      fp->uf_tml_self[fp->uf_tml_idx] = +        profile_self(fp->uf_tml_self[fp->uf_tml_idx], fp->uf_tml_start, +          fp->uf_tml_children);      }      fp->uf_tml_idx = -1;    } | 
