Hi Bram et al.,
I'm doing some performance investigations of Vim code trying to understand
whether there are any possibilities to improve it.
Currently I've made the following observations (all investigations are done on
Windows):
Redundant work is done during regexp operations in syntax highlighting. On some
files it is very noticable. The stack of the hotspot is ... > syn_current_attr
> syn_regexec > vim_regexec_multi > vim_regexec_both > regtry > regmatch >
ga_grow > alloc_clear > memset. So alloc_clear spends quite a few clockticks in
lalloc() and memset().
The reason for this is pessimistically big grow size for regset growing array:
ga_init2(®stack, 1, 10000);
This is not very good: many regexp operations don't go deep - non-match is
detected very quickly. But even one element on the stack will lead to
allocating at least 10000 bytes (which should be fast with good CRT memory
allocator) and (worse) initializing these 10000 bytes with zeros (won't be that
fast).
One possible solution would be to keep regstack alive across calls to
vim_regexec_both, but I'm not sure if it's can be done safely. What I did was
replacing the grow size with smaller number and making the grow size for
growing arrays dynamic with increase of 25%:
--- regexp.c (revision 136)
+++ regexp.c (working copy)
@@ -3350,7 +3350,7 @@
/* Init the regstack empty. Use an item size of 1 byte, since we push
* different things onto it. Use a large grow size to avoid reallocating
* it too often. */
- ga_init2(®stack, 1, 10000);
+ ga_init2(®stack, 1, 64);
/* Init the backpos table empty. */
ga_init2(&backpos, sizeof(backpos_T), 10);
--- misc2.c (revision 136)
+++ misc2.c (working copy)
@@ -1905,6 +1905,7 @@
{
if (n < gap->ga_growsize)
n = gap->ga_growsize;
+ gap->ga_growsize += (gap->ga_growsize >> 2);
len = gap->ga_itemsize * (gap->ga_len + n);
pp = alloc_clear((unsigned)len);
if (pp == NULL)
With this change I can see serious performance improvements, but I'm not sure
if they are safe.
Bram, does it look making any sense?
--
Alexei Alexandrov