Patch 8.2.2530
Problem:    Vim9: not enough testing for profiling.
Solution:   Add a test with nested functions and a lambda.  Fix profiling
            for calling a compiled function.
Files:      src/profiler.c, src/proto/profiler.pro, src/userfunc.c,
            src/vim9execute.c, src/testdir/test_profile.vim


*** ../vim-8.2.2529/src/profiler.c      2021-01-24 12:53:30.784247042 +0100
--- src/profiler.c      2021-02-18 21:52:38.477222997 +0100
***************
*** 558,581 ****
   * When calling a function: may initialize for profiling.
   */
      void
! profile_may_start_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc)
  {
!     if (do_profiling == PROF_YES)
      {
!       if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
!       {
!           info->pi_started_profiling = TRUE;
!           func_do_profile(fp);
!       }
!       if (fp->uf_profiling
!                   || (fc->caller != NULL && fc->caller->func->uf_profiling))
!       {
!           ++fp->uf_tm_count;
!           profile_start(&info->pi_call_start);
!           profile_zero(&fp->uf_tm_children);
!       }
!       script_prof_save(&info->pi_wait_start);
      }
  }
  
  /*
--- 558,577 ----
   * When calling a function: may initialize for profiling.
   */
      void
! profile_may_start_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller)
  {
!     if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
      {
!       info->pi_started_profiling = TRUE;
!       func_do_profile(fp);
      }
+     if (fp->uf_profiling || (caller != NULL && caller->uf_profiling))
+     {
+       ++fp->uf_tm_count;
+       profile_start(&info->pi_call_start);
+       profile_zero(&fp->uf_tm_children);
+     }
+     script_prof_save(&info->pi_wait_start);
  }
  
  /*
***************
*** 583,598 ****
   * must have been called previously.
   */
      void
! profile_may_end_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc)
  {
      profile_end(&info->pi_call_start);
      profile_sub_wait(&info->pi_wait_start, &info->pi_call_start);
      profile_add(&fp->uf_tm_total, &info->pi_call_start);
      profile_self(&fp->uf_tm_self, &info->pi_call_start, &fp->uf_tm_children);
!     if (fc->caller != NULL && fc->caller->func->uf_profiling)
      {
!       profile_add(&fc->caller->func->uf_tm_children, &info->pi_call_start);
!       profile_add(&fc->caller->func->uf_tml_children, &info->pi_call_start);
      }
      if (info->pi_started_profiling)
        // make a ":profdel func" stop profiling the function
--- 579,594 ----
   * must have been called previously.
   */
      void
! profile_may_end_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller)
  {
      profile_end(&info->pi_call_start);
      profile_sub_wait(&info->pi_wait_start, &info->pi_call_start);
      profile_add(&fp->uf_tm_total, &info->pi_call_start);
      profile_self(&fp->uf_tm_self, &info->pi_call_start, &fp->uf_tm_children);
!     if (caller != NULL && caller->uf_profiling)
      {
!       profile_add(&caller->uf_tm_children, &info->pi_call_start);
!       profile_add(&caller->uf_tml_children, &info->pi_call_start);
      }
      if (info->pi_started_profiling)
        // make a ":profdel func" stop profiling the function
*** ../vim-8.2.2529/src/proto/profiler.pro      2021-01-24 12:53:30.784247042 
+0100
--- src/proto/profiler.pro      2021-02-18 21:45:08.638264166 +0100
***************
*** 19,26 ****
  void prof_inchar_exit(void);
  int prof_def_func(void);
  void func_do_profile(ufunc_T *fp);
! void profile_may_start_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc);
! void profile_may_end_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc);
  void prof_child_enter(proftime_T *tm);
  void prof_child_exit(proftime_T *tm);
  void func_line_start(void *cookie, long lnum);
--- 19,26 ----
  void prof_inchar_exit(void);
  int prof_def_func(void);
  void func_do_profile(ufunc_T *fp);
! void profile_may_start_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller);
! void profile_may_end_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller);
  void prof_child_enter(proftime_T *tm);
  void prof_child_exit(proftime_T *tm);
  void func_line_start(void *cookie, long lnum);
*** ../vim-8.2.2529/src/userfunc.c      2021-02-12 22:10:18.227311434 +0100
--- src/userfunc.c      2021-02-18 21:58:28.320397956 +0100
***************
*** 1649,1664 ****
  
      if (fp->uf_def_status != UF_NOT_COMPILED)
      {
        // Execute the function, possibly compiling it first.
  #ifdef FEAT_PROFILE
!       profile_may_start_func(&profile_info, fp, fc);
  #endif
        call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
        funcdepth_decrement();
  #ifdef FEAT_PROFILE
        if (do_profiling == PROF_YES && (fp->uf_profiling
!                   || (fc->caller != NULL && fc->caller->func->uf_profiling)))
!           profile_may_end_func(&profile_info, fp, fc);
  #endif
        current_funccal = fc->caller;
        free_funccal(fc);
--- 1649,1668 ----
  
      if (fp->uf_def_status != UF_NOT_COMPILED)
      {
+ #ifdef FEAT_PROFILE
+       ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func;
+ #endif
        // Execute the function, possibly compiling it first.
  #ifdef FEAT_PROFILE
!       if (do_profiling == PROF_YES)
!           profile_may_start_func(&profile_info, fp, caller);
  #endif
        call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
        funcdepth_decrement();
  #ifdef FEAT_PROFILE
        if (do_profiling == PROF_YES && (fp->uf_profiling
!                                 || (caller != NULL && caller->uf_profiling)))
!           profile_may_end_func(&profile_info, fp, caller);
  #endif
        current_funccal = fc->caller;
        free_funccal(fc);
***************
*** 1872,1878 ****
        --no_wait_return;
      }
  #ifdef FEAT_PROFILE
!     profile_may_start_func(&profile_info, fp, fc);
  #endif
  
      save_current_sctx = current_sctx;
--- 1876,1884 ----
        --no_wait_return;
      }
  #ifdef FEAT_PROFILE
!     if (do_profiling == PROF_YES)
!       profile_may_start_func(&profile_info, fp,
!                                fc->caller == NULL ? NULL : fc->caller->func);
  #endif
  
      save_current_sctx = current_sctx;
***************
*** 1908,1916 ****
      }
  
  #ifdef FEAT_PROFILE
!     if (do_profiling == PROF_YES && (fp->uf_profiling
!                   || (fc->caller != NULL && fc->caller->func->uf_profiling)))
!       profile_may_end_func(&profile_info, fp, fc);
  #endif
  
      // when being verbose, mention the return value
--- 1914,1926 ----
      }
  
  #ifdef FEAT_PROFILE
!     if (do_profiling == PROF_YES)
!     {
!       ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func;
! 
!       if (fp->uf_profiling || (caller != NULL && caller->uf_profiling))
!           profile_may_end_func(&profile_info, fp, caller);
!     }
  #endif
  
      // when being verbose, mention the return value
*** ../vim-8.2.2529/src/vim9execute.c   2021-02-13 18:32:59.264950079 +0100
--- src/vim9execute.c   2021-02-19 18:55:14.966685962 +0100
***************
*** 72,77 ****
--- 72,82 ----
      garray_T  ec_funcrefs;    // partials that might be a closure
  };
  
+ #ifdef FEAT_PROFILE
+ // stack of profinfo_T used when profiling.
+ static garray_T profile_info_ga = {0, 0, sizeof(profinfo_T), 20, NULL};
+ #endif
+ 
  // Get pointer to item relative to the bottom of the stack, -1 is the last 
one.
  #define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + 
ectx->ec_stack.ga_len + (idx))
  
***************
*** 184,196 ****
      }
  
  #ifdef FEAT_PROFILE
!     // Profiling might be enabled/disabled along the way.  This should not
!     // fail, since the function was compiled before and toggling profiling
!     // doesn't change any errors.
!     if (func_needs_compiling(ufunc, PROFILING(ufunc))
!           && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
                                                                       == FAIL)
!       return FAIL;
  #endif
  
      if (ufunc->uf_va_name != NULL)
--- 189,215 ----
      }
  
  #ifdef FEAT_PROFILE
!     if (do_profiling == PROF_YES)
!     {
!       if (ga_grow(&profile_info_ga, 1) == OK)
!       {
!           profinfo_T *info = ((profinfo_T *)profile_info_ga.ga_data)
!                                                     + profile_info_ga.ga_len;
!           ++profile_info_ga.ga_len;
!           CLEAR_POINTER(info);
!           profile_may_start_func(info, ufunc,
!                       (((dfunc_T *)def_functions.ga_data)
!                                             + ectx->ec_dfunc_idx)->df_ufunc);
!       }
! 
!       // Profiling might be enabled/disabled along the way.  This should not
!       // fail, since the function was compiled before and toggling profiling
!       // doesn't change any errors.
!       if (func_needs_compiling(ufunc, PROFILING(ufunc))
!               && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
                                                                       == FAIL)
!           return FAIL;
!     }
  #endif
  
      if (ufunc->uf_va_name != NULL)
***************
*** 517,523 ****
--- 536,560 ----
      int               argcount = ufunc_argcount(dfunc->df_ufunc);
      int               top = ectx->ec_frame_idx - argcount;
      estack_T  *entry;
+     int               prev_dfunc_idx = STACK_TV(ectx->ec_frame_idx
+                                       + STACK_FRAME_FUNC_OFF)->vval.v_number;
+     dfunc_T   *prev_dfunc = ((dfunc_T *)def_functions.ga_data)
+                                                             + prev_dfunc_idx;
  
+ #ifdef FEAT_PROFILE
+     if (do_profiling == PROF_YES)
+     {
+       ufunc_T *caller = prev_dfunc->df_ufunc;
+ 
+       if (dfunc->df_ufunc->uf_profiling
+                                  || (caller != NULL && caller->uf_profiling))
+       {
+           profile_may_end_func(((profinfo_T *)profile_info_ga.ga_data)
+                       + profile_info_ga.ga_len - 1, dfunc->df_ufunc, caller);
+           --profile_info_ga.ga_len;
+       }
+     }
+ #endif
      // execution context goes one level up
      entry = estack_pop();
      if (entry != NULL)
***************
*** 544,551 ****
      vim_free(ectx->ec_outer);
  
      // Restore the previous frame.
!     ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx
!                                       + STACK_FRAME_FUNC_OFF)->vval.v_number;
      ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx
                                        + STACK_FRAME_IIDX_OFF)->vval.v_number;
      ectx->ec_outer = (void *)STACK_TV(ectx->ec_frame_idx
--- 581,587 ----
      vim_free(ectx->ec_outer);
  
      // Restore the previous frame.
!     ectx->ec_dfunc_idx = prev_dfunc_idx;
      ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx
                                        + STACK_FRAME_IIDX_OFF)->vval.v_number;
      ectx->ec_outer = (void *)STACK_TV(ectx->ec_frame_idx
***************
*** 553,560 ****
      // restoring ec_frame_idx must be last
      ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx
                                       + STACK_FRAME_IDX_OFF)->vval.v_number;
!     dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
!     ectx->ec_instr = INSTRUCTIONS(dfunc);
  
      if (ret_idx > 0)
      {
--- 589,595 ----
      // restoring ec_frame_idx must be last
      ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx
                                       + STACK_FRAME_IDX_OFF)->vval.v_number;
!     ectx->ec_instr = INSTRUCTIONS(prev_dfunc);
  
      if (ret_idx > 0)
      {
*** ../vim-8.2.2529/src/testdir/test_profile.vim        2021-01-26 
12:06:27.465801087 +0100
--- src/testdir/test_profile.vim        2021-02-19 19:08:59.764522006 +0100
***************
*** 605,609 ****
--- 605,642 ----
    call delete('Xprofile_crash.log')
  endfunc
  
+ func Test_vim9_nested_call()
+   let lines =<< trim END
+     vim9script
+     var total = 0
+     def One(Ref: func(number))
+       for i in range(3)
+         Ref(i)
+       endfor
+     enddef
+     def Two(nr: number)
+       total += nr
+     enddef
+     prof start Xprofile_nested.log
+     prof func One
+     prof func Two
+     One((nr) => Two(nr))
+     assert_equal(3, total)
+   END
+   call writefile(lines, 'Xprofile_nested.vim')
+   call system(GetVimCommandClean() . ' -es -c "so Xprofile_nested.vim" -c q')
+   call assert_equal(0, v:shell_error)
+ 
+   let prof_lines = readfile('Xprofile_nested.log')->join('#')
+   call assert_match('FUNCTION  <SNR>\d\+_One().*'
+         \ .. '#Called 1 time.*'
+         \ .. '#    1 \s*[0-9.]\+   for i in range(3)'
+         \ .. '#    3 \s*[0-9.]\+ \s*[0-9.]\+     Ref(i)'
+         \ .. '#    3 \s*[0-9.]\+   endfor', prof_lines)
+   call assert_match('FUNCTION  <SNR>\d\+_Two().*'
+         \ .. '#Called 3 times.*'
+         \ .. '#    3 \s*[0-9.]\+   total += nr', prof_lines)
+ endfunc
+ 
  
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.2529/src/version.c       2021-02-17 21:56:59.909196307 +0100
--- src/version.c       2021-02-18 21:15:08.622333394 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2530,
  /**/

-- 
TALL KNIGHT: We are now no longer the Knights Who Say Ni!
ONE KNIGHT:  Ni!
OTHERS:      Sh!
ONE KNIGHT:  (whispers) Sorry.
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202102191813.11JIDlEj2771436%40masaka.moolenaar.net.

Raspunde prin e-mail lui