Skip to content

Commit 12d2653

Browse files
committed
patch 8.2.2530: Vim9: not enough testing for profiling
Problem: Vim9: not enough testing for profiling. Solution: Add a test with nested functions and a lambda. Fix profiling for calling a compiled function.
1 parent d3f8a9e commit 12d2653

6 files changed

Lines changed: 114 additions & 38 deletions

File tree

src/profiler.c

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -558,41 +558,37 @@ func_do_profile(ufunc_T *fp)
558558
* When calling a function: may initialize for profiling.
559559
*/
560560
void
561-
profile_may_start_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc)
561+
profile_may_start_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller)
562562
{
563-
if (do_profiling == PROF_YES)
563+
if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
564564
{
565-
if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL))
566-
{
567-
info->pi_started_profiling = TRUE;
568-
func_do_profile(fp);
569-
}
570-
if (fp->uf_profiling
571-
|| (fc->caller != NULL && fc->caller->func->uf_profiling))
572-
{
573-
++fp->uf_tm_count;
574-
profile_start(&info->pi_call_start);
575-
profile_zero(&fp->uf_tm_children);
576-
}
577-
script_prof_save(&info->pi_wait_start);
565+
info->pi_started_profiling = TRUE;
566+
func_do_profile(fp);
567+
}
568+
if (fp->uf_profiling || (caller != NULL && caller->uf_profiling))
569+
{
570+
++fp->uf_tm_count;
571+
profile_start(&info->pi_call_start);
572+
profile_zero(&fp->uf_tm_children);
578573
}
574+
script_prof_save(&info->pi_wait_start);
579575
}
580576

581577
/*
582578
* After calling a function: may handle profiling. profile_may_start_func()
583579
* must have been called previously.
584580
*/
585581
void
586-
profile_may_end_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc)
582+
profile_may_end_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller)
587583
{
588584
profile_end(&info->pi_call_start);
589585
profile_sub_wait(&info->pi_wait_start, &info->pi_call_start);
590586
profile_add(&fp->uf_tm_total, &info->pi_call_start);
591587
profile_self(&fp->uf_tm_self, &info->pi_call_start, &fp->uf_tm_children);
592-
if (fc->caller != NULL && fc->caller->func->uf_profiling)
588+
if (caller != NULL && caller->uf_profiling)
593589
{
594-
profile_add(&fc->caller->func->uf_tm_children, &info->pi_call_start);
595-
profile_add(&fc->caller->func->uf_tml_children, &info->pi_call_start);
590+
profile_add(&caller->uf_tm_children, &info->pi_call_start);
591+
profile_add(&caller->uf_tml_children, &info->pi_call_start);
596592
}
597593
if (info->pi_started_profiling)
598594
// make a ":profdel func" stop profiling the function

src/proto/profiler.pro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ void prof_inchar_enter(void);
1919
void prof_inchar_exit(void);
2020
int prof_def_func(void);
2121
void func_do_profile(ufunc_T *fp);
22-
void profile_may_start_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc);
23-
void profile_may_end_func(profinfo_T *info, ufunc_T *fp, funccall_T *fc);
22+
void profile_may_start_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller);
23+
void profile_may_end_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller);
2424
void prof_child_enter(proftime_T *tm);
2525
void prof_child_exit(proftime_T *tm);
2626
void func_line_start(void *cookie, long lnum);

src/testdir/test_profile.vim

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,5 +605,38 @@ func Test_vim9_profiling()
605605
call delete('Xprofile_crash.log')
606606
endfunc
607607

608+
func Test_vim9_nested_call()
609+
let lines =<< trim END
610+
vim9script
611+
var total = 0
612+
def One(Ref: func(number))
613+
for i in range(3)
614+
Ref(i)
615+
endfor
616+
enddef
617+
def Two(nr: number)
618+
total += nr
619+
enddef
620+
prof start Xprofile_nested.log
621+
prof func One
622+
prof func Two
623+
One((nr) => Two(nr))
624+
assert_equal(3, total)
625+
END
626+
call writefile(lines, 'Xprofile_nested.vim')
627+
call system(GetVimCommandClean() . ' -es -c "so Xprofile_nested.vim" -c q')
628+
call assert_equal(0, v:shell_error)
629+
630+
let prof_lines = readfile('Xprofile_nested.log')->join('#')
631+
call assert_match('FUNCTION <SNR>\d\+_One().*'
632+
\ .. '#Called 1 time.*'
633+
\ .. '# 1 \s*[0-9.]\+ for i in range(3)'
634+
\ .. '# 3 \s*[0-9.]\+ \s*[0-9.]\+ Ref(i)'
635+
\ .. '# 3 \s*[0-9.]\+ endfor', prof_lines)
636+
call assert_match('FUNCTION <SNR>\d\+_Two().*'
637+
\ .. '#Called 3 times.*'
638+
\ .. '# 3 \s*[0-9.]\+ total += nr', prof_lines)
639+
endfunc
640+
608641

609642
" vim: shiftwidth=2 sts=2 expandtab

src/userfunc.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,16 +1649,20 @@ call_user_func(
16491649

16501650
if (fp->uf_def_status != UF_NOT_COMPILED)
16511651
{
1652+
#ifdef FEAT_PROFILE
1653+
ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func;
1654+
#endif
16521655
// Execute the function, possibly compiling it first.
16531656
#ifdef FEAT_PROFILE
1654-
profile_may_start_func(&profile_info, fp, fc);
1657+
if (do_profiling == PROF_YES)
1658+
profile_may_start_func(&profile_info, fp, caller);
16551659
#endif
16561660
call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
16571661
funcdepth_decrement();
16581662
#ifdef FEAT_PROFILE
16591663
if (do_profiling == PROF_YES && (fp->uf_profiling
1660-
|| (fc->caller != NULL && fc->caller->func->uf_profiling)))
1661-
profile_may_end_func(&profile_info, fp, fc);
1664+
|| (caller != NULL && caller->uf_profiling)))
1665+
profile_may_end_func(&profile_info, fp, caller);
16621666
#endif
16631667
current_funccal = fc->caller;
16641668
free_funccal(fc);
@@ -1872,7 +1876,9 @@ call_user_func(
18721876
--no_wait_return;
18731877
}
18741878
#ifdef FEAT_PROFILE
1875-
profile_may_start_func(&profile_info, fp, fc);
1879+
if (do_profiling == PROF_YES)
1880+
profile_may_start_func(&profile_info, fp,
1881+
fc->caller == NULL ? NULL : fc->caller->func);
18761882
#endif
18771883

18781884
save_current_sctx = current_sctx;
@@ -1908,9 +1914,13 @@ call_user_func(
19081914
}
19091915

19101916
#ifdef FEAT_PROFILE
1911-
if (do_profiling == PROF_YES && (fp->uf_profiling
1912-
|| (fc->caller != NULL && fc->caller->func->uf_profiling)))
1913-
profile_may_end_func(&profile_info, fp, fc);
1917+
if (do_profiling == PROF_YES)
1918+
{
1919+
ufunc_T *caller = fc->caller == NULL ? NULL : fc->caller->func;
1920+
1921+
if (fp->uf_profiling || (caller != NULL && caller->uf_profiling))
1922+
profile_may_end_func(&profile_info, fp, caller);
1923+
}
19141924
#endif
19151925

19161926
// when being verbose, mention the return value

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2530,
753755
/**/
754756
2529,
755757
/**/

src/vim9execute.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ struct ectx_S {
7272
garray_T ec_funcrefs; // partials that might be a closure
7373
};
7474

75+
#ifdef FEAT_PROFILE
76+
// stack of profinfo_T used when profiling.
77+
static garray_T profile_info_ga = {0, 0, sizeof(profinfo_T), 20, NULL};
78+
#endif
79+
7580
// Get pointer to item relative to the bottom of the stack, -1 is the last one.
7681
#define STACK_TV_BOT(idx) (((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_stack.ga_len + (idx))
7782

@@ -184,13 +189,27 @@ call_dfunc(int cdf_idx, partial_T *pt, int argcount_arg, ectx_T *ectx)
184189
}
185190

186191
#ifdef FEAT_PROFILE
187-
// Profiling might be enabled/disabled along the way. This should not
188-
// fail, since the function was compiled before and toggling profiling
189-
// doesn't change any errors.
190-
if (func_needs_compiling(ufunc, PROFILING(ufunc))
191-
&& compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
192+
if (do_profiling == PROF_YES)
193+
{
194+
if (ga_grow(&profile_info_ga, 1) == OK)
195+
{
196+
profinfo_T *info = ((profinfo_T *)profile_info_ga.ga_data)
197+
+ profile_info_ga.ga_len;
198+
++profile_info_ga.ga_len;
199+
CLEAR_POINTER(info);
200+
profile_may_start_func(info, ufunc,
201+
(((dfunc_T *)def_functions.ga_data)
202+
+ ectx->ec_dfunc_idx)->df_ufunc);
203+
}
204+
205+
// Profiling might be enabled/disabled along the way. This should not
206+
// fail, since the function was compiled before and toggling profiling
207+
// doesn't change any errors.
208+
if (func_needs_compiling(ufunc, PROFILING(ufunc))
209+
&& compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL)
192210
== FAIL)
193-
return FAIL;
211+
return FAIL;
212+
}
194213
#endif
195214

196215
if (ufunc->uf_va_name != NULL)
@@ -517,7 +536,25 @@ func_return(ectx_T *ectx)
517536
int argcount = ufunc_argcount(dfunc->df_ufunc);
518537
int top = ectx->ec_frame_idx - argcount;
519538
estack_T *entry;
539+
int prev_dfunc_idx = STACK_TV(ectx->ec_frame_idx
540+
+ STACK_FRAME_FUNC_OFF)->vval.v_number;
541+
dfunc_T *prev_dfunc = ((dfunc_T *)def_functions.ga_data)
542+
+ prev_dfunc_idx;
520543

544+
#ifdef FEAT_PROFILE
545+
if (do_profiling == PROF_YES)
546+
{
547+
ufunc_T *caller = prev_dfunc->df_ufunc;
548+
549+
if (dfunc->df_ufunc->uf_profiling
550+
|| (caller != NULL && caller->uf_profiling))
551+
{
552+
profile_may_end_func(((profinfo_T *)profile_info_ga.ga_data)
553+
+ profile_info_ga.ga_len - 1, dfunc->df_ufunc, caller);
554+
--profile_info_ga.ga_len;
555+
}
556+
}
557+
#endif
521558
// execution context goes one level up
522559
entry = estack_pop();
523560
if (entry != NULL)
@@ -544,17 +581,15 @@ func_return(ectx_T *ectx)
544581
vim_free(ectx->ec_outer);
545582

546583
// Restore the previous frame.
547-
ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx
548-
+ STACK_FRAME_FUNC_OFF)->vval.v_number;
584+
ectx->ec_dfunc_idx = prev_dfunc_idx;
549585
ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx
550586
+ STACK_FRAME_IIDX_OFF)->vval.v_number;
551587
ectx->ec_outer = (void *)STACK_TV(ectx->ec_frame_idx
552588
+ STACK_FRAME_OUTER_OFF)->vval.v_string;
553589
// restoring ec_frame_idx must be last
554590
ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx
555591
+ STACK_FRAME_IDX_OFF)->vval.v_number;
556-
dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx;
557-
ectx->ec_instr = INSTRUCTIONS(dfunc);
592+
ectx->ec_instr = INSTRUCTIONS(prev_dfunc);
558593

559594
if (ret_idx > 0)
560595
{

0 commit comments

Comments
 (0)