Mercurial > vim
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 */ |