comparison src/userfunc.c @ 17370:ba06a1c42274 v8.1.1684

patch 8.1.1684: profiling functionality is spread out commit https://github.com/vim/vim/commit/fa55cfc69d2b14761e2a8bd85bc1e0d82df770aa Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jul 13 22:59:32 2019 +0200 patch 8.1.1684: profiling functionality is spread out Problem: Profiling functionality is spread out. Solution: Put profiling functionality in profiling.c. (Yegappan Lakshmanan, closes #4666)
author Bram Moolenaar <Bram@vim.org>
date Sat, 13 Jul 2019 23:00:06 +0200
parents 984eef966002
children 8f44c630c366
comparison
equal deleted inserted replaced
17369:4b97e0731720 17370:ba06a1c42274
27 #define UF2HIKEY(fp) ((fp)->uf_name) 27 #define UF2HIKEY(fp) ((fp)->uf_name)
28 #define HIKEY2UF(p) ((ufunc_T *)((p) - offsetof(ufunc_T, uf_name))) 28 #define HIKEY2UF(p) ((ufunc_T *)((p) - offsetof(ufunc_T, uf_name)))
29 #define HI2UF(hi) HIKEY2UF((hi)->hi_key) 29 #define HI2UF(hi) HIKEY2UF((hi)->hi_key)
30 30
31 #define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j] 31 #define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
32 #define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
33 32
34 /* 33 /*
35 * All user-defined functions are found in this hashtable. 34 * All user-defined functions are found in this hashtable.
36 */ 35 */
37 static hashtab_T func_hashtab; 36 static hashtab_T func_hashtab;
49 static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it"); 48 static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
50 static char *e_funcdict = N_("E717: Dictionary entry already exists"); 49 static char *e_funcdict = N_("E717: Dictionary entry already exists");
51 static char *e_funcref = N_("E718: Funcref required"); 50 static char *e_funcref = N_("E718: Funcref required");
52 static char *e_nofunc = N_("E130: Unknown function: %s"); 51 static char *e_nofunc = N_("E130: Unknown function: %s");
53 52
54 #ifdef FEAT_PROFILE
55 static void func_do_profile(ufunc_T *fp);
56 static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self);
57 static void prof_func_line(FILE *fd, int count, proftime_T *total, proftime_T *self, int prefer_self);
58 static int prof_total_cmp(const void *s1, const void *s2);
59 static int prof_self_cmp(const void *s1, const void *s2);
60 #endif
61 static void funccal_unref(funccall_T *fc, ufunc_T *fp, int force); 53 static void funccal_unref(funccall_T *fc, ufunc_T *fp, int force);
62 54
63 void 55 void
64 func_init() 56 func_init()
65 { 57 {
1308 else 1300 else
1309 { 1301 {
1310 current_funccal = funccal_stack->top_funccal; 1302 current_funccal = funccal_stack->top_funccal;
1311 funccal_stack = funccal_stack->next; 1303 funccal_stack = funccal_stack->next;
1312 } 1304 }
1305 }
1306
1307 funccall_T *
1308 get_current_funccal(void)
1309 {
1310 return current_funccal;
1313 } 1311 }
1314 1312
1315 #if defined(EXITFREE) || defined(PROTO) 1313 #if defined(EXITFREE) || defined(PROTO)
1316 void 1314 void
1317 free_all_functions(void) 1315 free_all_functions(void)
2760 return NULL; 2758 return NULL;
2761 } 2759 }
2762 #endif 2760 #endif
2763 2761
2764 #if defined(FEAT_PROFILE) || defined(PROTO) 2762 #if defined(FEAT_PROFILE) || defined(PROTO)
2765 /*
2766 * Start profiling function "fp".
2767 */
2768 static void
2769 func_do_profile(ufunc_T *fp)
2770 {
2771 int len = fp->uf_lines.ga_len;
2772
2773 if (!fp->uf_prof_initialized)
2774 {
2775 if (len == 0)
2776 len = 1; /* avoid getting error for allocating zero bytes */
2777 fp->uf_tm_count = 0;
2778 profile_zero(&fp->uf_tm_self);
2779 profile_zero(&fp->uf_tm_total);
2780 if (fp->uf_tml_count == NULL)
2781 fp->uf_tml_count = ALLOC_CLEAR_MULT(int, len);
2782 if (fp->uf_tml_total == NULL)
2783 fp->uf_tml_total = ALLOC_CLEAR_MULT(proftime_T, len);
2784 if (fp->uf_tml_self == NULL)
2785 fp->uf_tml_self = ALLOC_CLEAR_MULT(proftime_T, len);
2786 fp->uf_tml_idx = -1;
2787 if (fp->uf_tml_count == NULL || fp->uf_tml_total == NULL
2788 || fp->uf_tml_self == NULL)
2789 return; /* out of memory */
2790 fp->uf_prof_initialized = TRUE;
2791 }
2792
2793 fp->uf_profiling = TRUE;
2794 }
2795 2763
2796 /* 2764 /*
2797 * Dump the profiling results for all functions in file "fd". 2765 * Dump the profiling results for all functions in file "fd".
2798 */ 2766 */
2799 void 2767 void
2869 } 2837 }
2870 2838
2871 vim_free(sorttab); 2839 vim_free(sorttab);
2872 } 2840 }
2873 2841
2874 static void
2875 prof_sort_list(
2876 FILE *fd,
2877 ufunc_T **sorttab,
2878 int st_len,
2879 char *title,
2880 int prefer_self) /* when equal print only self time */
2881 {
2882 int i;
2883 ufunc_T *fp;
2884
2885 fprintf(fd, "FUNCTIONS SORTED ON %s TIME\n", title);
2886 fprintf(fd, "count total (s) self (s) function\n");
2887 for (i = 0; i < 20 && i < st_len; ++i)
2888 {
2889 fp = sorttab[i];
2890 prof_func_line(fd, fp->uf_tm_count, &fp->uf_tm_total, &fp->uf_tm_self,
2891 prefer_self);
2892 if (fp->uf_name[0] == K_SPECIAL)
2893 fprintf(fd, " <SNR>%s()\n", fp->uf_name + 3);
2894 else
2895 fprintf(fd, " %s()\n", fp->uf_name);
2896 }
2897 fprintf(fd, "\n");
2898 }
2899
2900 /*
2901 * Print the count and times for one function or function line.
2902 */
2903 static void
2904 prof_func_line(
2905 FILE *fd,
2906 int count,
2907 proftime_T *total,
2908 proftime_T *self,
2909 int prefer_self) /* when equal print only self time */
2910 {
2911 if (count > 0)
2912 {
2913 fprintf(fd, "%5d ", count);
2914 if (prefer_self && profile_equal(total, self))
2915 fprintf(fd, " ");
2916 else
2917 fprintf(fd, "%s ", profile_msg(total));
2918 if (!prefer_self && profile_equal(total, self))
2919 fprintf(fd, " ");
2920 else
2921 fprintf(fd, "%s ", profile_msg(self));
2922 }
2923 else
2924 fprintf(fd, " ");
2925 }
2926
2927 /*
2928 * Compare function for total time sorting.
2929 */
2930 static int
2931 prof_total_cmp(const void *s1, const void *s2)
2932 {
2933 ufunc_T *p1, *p2;
2934
2935 p1 = *(ufunc_T **)s1;
2936 p2 = *(ufunc_T **)s2;
2937 return profile_cmp(&p1->uf_tm_total, &p2->uf_tm_total);
2938 }
2939
2940 /*
2941 * Compare function for self time sorting.
2942 */
2943 static int
2944 prof_self_cmp(const void *s1, const void *s2)
2945 {
2946 ufunc_T *p1, *p2;
2947
2948 p1 = *(ufunc_T **)s1;
2949 p2 = *(ufunc_T **)s2;
2950 return profile_cmp(&p1->uf_tm_self, &p2->uf_tm_self);
2951 }
2952
2953 /*
2954 * Prepare profiling for entering a child or something else that is not
2955 * counted for the script/function itself.
2956 * Should always be called in pair with prof_child_exit().
2957 */
2958 void
2959 prof_child_enter(
2960 proftime_T *tm) /* place to store waittime */
2961 {
2962 funccall_T *fc = current_funccal;
2963
2964 if (fc != NULL && fc->func->uf_profiling)
2965 profile_start(&fc->prof_child);
2966 script_prof_save(tm);
2967 }
2968
2969 /*
2970 * Take care of time spent in a child.
2971 * Should always be called after prof_child_enter().
2972 */
2973 void
2974 prof_child_exit(
2975 proftime_T *tm) /* where waittime was stored */
2976 {
2977 funccall_T *fc = current_funccal;
2978
2979 if (fc != NULL && fc->func->uf_profiling)
2980 {
2981 profile_end(&fc->prof_child);
2982 profile_sub_wait(tm, &fc->prof_child); /* don't count waiting time */
2983 profile_add(&fc->func->uf_tm_children, &fc->prof_child);
2984 profile_add(&fc->func->uf_tml_children, &fc->prof_child);
2985 }
2986 script_prof_restore(tm);
2987 }
2988
2989 #endif /* FEAT_PROFILE */ 2842 #endif /* FEAT_PROFILE */
2990 2843
2991 #if defined(FEAT_CMDL_COMPL) || defined(PROTO) 2844 #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
2992 2845
2993 /* 2846 /*
3571 fcp->dbg_tick = debug_tick; 3424 fcp->dbg_tick = debug_tick;
3572 } 3425 }
3573 3426
3574 return retval; 3427 return retval;
3575 } 3428 }
3576
3577 #if defined(FEAT_PROFILE) || defined(PROTO)
3578 /*
3579 * Called when starting to read a function line.
3580 * "sourcing_lnum" must be correct!
3581 * When skipping lines it may not actually be executed, but we won't find out
3582 * until later and we need to store the time now.
3583 */
3584 void
3585 func_line_start(void *cookie)
3586 {
3587 funccall_T *fcp = (funccall_T *)cookie;
3588 ufunc_T *fp = fcp->func;
3589
3590 if (fp->uf_profiling && sourcing_lnum >= 1
3591 && sourcing_lnum <= fp->uf_lines.ga_len)
3592 {
3593 fp->uf_tml_idx = sourcing_lnum - 1;
3594 /* Skip continuation lines. */
3595 while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)
3596 --fp->uf_tml_idx;
3597 fp->uf_tml_execed = FALSE;
3598 profile_start(&fp->uf_tml_start);
3599 profile_zero(&fp->uf_tml_children);
3600 profile_get_wait(&fp->uf_tml_wait);
3601 }
3602 }
3603
3604 /*
3605 * Called when actually executing a function line.
3606 */
3607 void
3608 func_line_exec(void *cookie)
3609 {
3610 funccall_T *fcp = (funccall_T *)cookie;
3611 ufunc_T *fp = fcp->func;
3612
3613 if (fp->uf_profiling && fp->uf_tml_idx >= 0)
3614 fp->uf_tml_execed = TRUE;
3615 }
3616
3617 /*
3618 * Called when done with a function line.
3619 */
3620 void
3621 func_line_end(void *cookie)
3622 {
3623 funccall_T *fcp = (funccall_T *)cookie;
3624 ufunc_T *fp = fcp->func;
3625
3626 if (fp->uf_profiling && fp->uf_tml_idx >= 0)
3627 {
3628 if (fp->uf_tml_execed)
3629 {
3630 ++fp->uf_tml_count[fp->uf_tml_idx];
3631 profile_end(&fp->uf_tml_start);
3632 profile_sub_wait(&fp->uf_tml_wait, &fp->uf_tml_start);
3633 profile_add(&fp->uf_tml_total[fp->uf_tml_idx], &fp->uf_tml_start);
3634 profile_self(&fp->uf_tml_self[fp->uf_tml_idx], &fp->uf_tml_start,
3635 &fp->uf_tml_children);
3636 }
3637 fp->uf_tml_idx = -1;
3638 }
3639 }
3640 #endif
3641 3429
3642 /* 3430 /*
3643 * Return TRUE if the currently active function should be ended, because a 3431 * Return TRUE if the currently active function should be ended, because a
3644 * return was encountered or an error occurred. Used inside a ":while". 3432 * return was encountered or an error occurred. Used inside a ":while".
3645 */ 3433 */