comparison src/debugger.c @ 33119:bede81965821 v9.0.1842

patch 9.0.1842: Need more accurate profiling Commit: https://github.com/vim/vim/commit/21d3212361f687704acb52cad7c1b9228e7c83f0 Author: Ernie Rael <errael@raelity.com> Date: Sat Sep 2 15:09:18 2023 +0200 patch 9.0.1842: Need more accurate profiling Problem: Need more accurate profiling Solution: Improve profiling results closes: #12192 Reduce overhead of checking if a function should be profiled, by caching results of checking (which are done with regexp). Cache uf_hash for uf_name in ufunc_T. Cache cleared when regexps are changed. Break at first match for has_profiling lookup. Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com>
author Christian Brabandt <cb@256bit.org>
date Sat, 02 Sep 2023 15:15:06 +0200
parents 695b50472e85
children 3af53f2895dc
comparison
equal deleted inserted replaced
33118:67f506069462 33119:bede81965821
526 static int has_expr_breakpoint = FALSE; 526 static int has_expr_breakpoint = FALSE;
527 527
528 #ifdef FEAT_PROFILE 528 #ifdef FEAT_PROFILE
529 // Profiling uses file and func names similar to breakpoints. 529 // Profiling uses file and func names similar to breakpoints.
530 static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL}; 530 static garray_T prof_ga = {0, 0, sizeof(struct debuggy), 4, NULL};
531
532 // Profiling caches results of regexp lookups for function/script name.
533 #define N_PROF_HTAB 2
534 static hashtab_T prof_cache[N_PROF_HTAB];
535 #define PROF_HTAB_FUNCS 0
536 #define PROF_HTAB_FILES 1
537 static int prof_cache_initialized;
538 typedef struct profentry_S
539 {
540 char pen_flags; // cache data booleans: profiling, forceit
541 char_u pen_name[1]; // actually longer
542 } profentry_T;
543 #define PEN_FLAG_PROFILING 1
544 #define PEN_FLAG_FORCEIT 2
545 #define PEN_SET_PROFILING(pe) ((pe)->pen_flags |= PEN_FLAG_PROFILING)
546 #define PEN_SET_FORCEIT(pe) ((pe)->pen_flags |= PEN_FLAG_FORCEIT)
547 #define PEN_IS_PROFILING(pe) (((pe)->pen_flags & PEN_FLAG_PROFILING) != 0)
548 #define PEN_IS_FORCEIT(pe) (((pe)->pen_flags & PEN_FLAG_FORCEIT) != 0)
549
550 #define PE2HIKEY(pe) ((pe)->pen_name)
551 #define HIKEY2PE(p) ((profentry_T *)((p) - (offsetof(profentry_T, pen_name))))
552 #define HI2PE(hi) HIKEY2PE((hi)->hi_key)
553
554 static void prof_clear_cache(void);
555 #define PROF_CLEAR_CACHE(gap) do {if ((gap) == &prof_ga) prof_clear_cache();} while (0)
556 // Can enable to get some info about profile caching
557 // #define PROF_CACHE_LOG
558 #else
559 #define PROF_CLEAR_CACHE(gap) do {} while (0)
531 #endif 560 #endif
532 #define DBG_FUNC 1 561 #define DBG_FUNC 1
533 #define DBG_FILE 2 562 #define DBG_FILE 2
534 #define DBG_EXPR 3 563 #define DBG_EXPR 3
535 564
706 { 735 {
707 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; 736 DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
708 ++debug_tick; 737 ++debug_tick;
709 } 738 }
710 ++gap->ga_len; 739 ++gap->ga_len;
740 PROF_CLEAR_CACHE(gap);
711 } 741 }
712 } 742 }
713 else 743 else
714 { 744 {
715 // DBG_EXPR 745 // DBG_EXPR
843 #endif 873 #endif
844 ++debug_tick; 874 ++debug_tick;
845 if (!del_all) 875 if (!del_all)
846 break; 876 break;
847 } 877 }
878 PROF_CLEAR_CACHE(gap);
848 879
849 // If all breakpoints were removed clear the array. 880 // If all breakpoints were removed clear the array.
850 if (gap->ga_len == 0) 881 if (gap->ga_len == 0)
851 ga_clear(gap); 882 ga_clear(gap);
852 if (gap == &dbg_breakp) 883 if (gap == &dbg_breakp)
897 { 928 {
898 return debuggy_find(file, fname, after, &dbg_breakp, NULL); 929 return debuggy_find(file, fname, after, &dbg_breakp, NULL);
899 } 930 }
900 931
901 #if defined(FEAT_PROFILE) || defined(PROTO) 932 #if defined(FEAT_PROFILE) || defined(PROTO)
933 #if defined(PROF_CACHE_LOG)
934 static int count_lookups[2];
935 #endif
902 /* 936 /*
903 * Return TRUE if profiling is on for a function or sourced file. 937 * Return TRUE if profiling is on for a function or sourced file.
938 * Cache the results of debuggy_find().
939 * Cache is cleared whenever prof_ga.ga_len is changed.
904 */ 940 */
905 int 941 int
906 has_profiling( 942 has_profiling(
907 int file, // TRUE for a file, FALSE for a function 943 int file, // TRUE for a file, FALSE for a function
908 char_u *fname, // file or function name 944 char_u *fname, // file or function name
909 int *fp) // return: forceit 945 int *fp, // return: forceit
910 { 946 hash_T *hashp) // use/return fname hash, may be NULL
911 return (debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp) 947 {
912 != (linenr_T)0); 948 if (prof_ga.ga_len == 0 || !prof_cache_initialized)
949 return debuggy_find(file, fname, (linenr_T)0, &prof_ga, fp)
950 != (linenr_T)0;
951
952 hash_T hash;
953 if (hashp != NULL)
954 {
955 hash = *hashp;
956 if (hash == 0)
957 {
958 hash = hash_hash(fname);
959 *hashp = hash;
960 }
961 }
962 else
963 hash = hash_hash(fname);
964
965 hashtab_T *ht = &prof_cache[file ? PROF_HTAB_FILES : PROF_HTAB_FUNCS];
966 hashitem_T *hi = hash_lookup(ht, fname, hash);
967 profentry_T *pe;
968 if (HASHITEM_EMPTY(hi))
969 {
970 pe = alloc(offsetof(profentry_T, pen_name) + STRLEN(fname) + 1);
971 if (pe == NULL)
972 return FALSE;
973 STRCPY(pe->pen_name, fname);
974 pe->pen_flags = 0;
975 // run debuggy_find and capture return and forceit
976 int f;
977 int lnum = debuggy_find(file, fname, (linenr_T)0, &prof_ga, &f);
978 if (lnum)
979 {
980 PEN_SET_PROFILING(pe);
981 if (f)
982 PEN_SET_FORCEIT(pe);
983 }
984 hash_add_item(ht, hi, pe->pen_name, hash);
985 #if defined(PROF_CACHE_LOG)
986 ch_log(NULL, "has_profiling: %s %s forceit %s, profile %s",
987 file ? "file" : "func", fname,
988 PEN_IS_FORCEIT(pe) ? "true" : "false",
989 PEN_IS_PROFILING(pe) ? "true" : "false");
990 #endif
991 }
992 else
993 pe = HI2PE(hi);
994 if (fp)
995 *fp = PEN_IS_FORCEIT(pe);
996 #if defined(PROF_CACHE_LOG)
997 count_lookups[file ? PROF_HTAB_FILES : PROF_HTAB_FUNCS]++;
998 #endif
999 return PEN_IS_PROFILING(pe);
1000 }
1001
1002 static void
1003 prof_clear_cache()
1004 {
1005 if (!prof_cache_initialized)
1006 {
1007 hash_init(&prof_cache[PROF_HTAB_FUNCS]);
1008 hash_init(&prof_cache[PROF_HTAB_FILES]);
1009 prof_cache_initialized = TRUE;
1010 }
1011
1012 hashtab_T *ht;
1013 for (ht = &prof_cache[0]; ht < &prof_cache[N_PROF_HTAB]; ht++)
1014 {
1015 if (ht->ht_used > 0)
1016 {
1017 #if defined(PROF_CACHE_LOG)
1018 int idx = ht == &prof_cache[PROF_HTAB_FUNCS]
1019 ? PROF_HTAB_FUNCS : PROF_HTAB_FILES;
1020 ch_log(NULL, "prof_clear_cache: %s, used: %ld, lookups: %d",
1021 idx == PROF_HTAB_FUNCS ? "function" : "script",
1022 ht->ht_used, count_lookups[idx]);
1023 count_lookups[idx] = 0;
1024 #endif
1025 hash_clear_all(ht, offsetof(profentry_T, pen_name));
1026 hash_init(ht);
1027 }
1028 }
913 } 1029 }
914 #endif 1030 #endif
915 1031
916 /* 1032 /*
917 * Common code for dbg_find_breakpoint() and has_profiling(). 1033 * Common code for dbg_find_breakpoint() and has_profiling().
977 lnum = bp->dbg_lnum; 1093 lnum = bp->dbg_lnum;
978 if (fp != NULL) 1094 if (fp != NULL)
979 *fp = bp->dbg_forceit; 1095 *fp = bp->dbg_forceit;
980 } 1096 }
981 got_int |= prev_got_int; 1097 got_int |= prev_got_int;
1098 #ifdef FEAT_PROFILE
1099 if (lnum && gap == &prof_ga)
1100 break;
1101 #endif
982 } 1102 }
983 #ifdef FEAT_EVAL 1103 #ifdef FEAT_EVAL
984 else if (bp->dbg_type == DBG_EXPR) 1104 else if (bp->dbg_type == DBG_EXPR)
985 { 1105 {
986 typval_T *tv; 1106 typval_T *tv;