blob: 504d71364756dcbf58a9852199a01aaaa8abc54a [file] [log] [blame]
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * profiler.c: vim script profiler
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_EVAL) || defined(PROTO)
17# if defined(FEAT_PROFILE) || defined(FEAT_RELTIME) || defined(PROTO)
18/*
19 * Store the current time in "tm".
20 */
21 void
22profile_start(proftime_T *tm)
23{
24# ifdef MSWIN
25 QueryPerformanceCounter(tm);
26# else
Ernie Rael076de792023-03-16 21:43:15 +000027 PROF_GET_TIME(tm);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020028# endif
29}
30
31/*
32 * Compute the elapsed time from "tm" till now and store in "tm".
33 */
34 void
35profile_end(proftime_T *tm)
36{
37 proftime_T now;
38
39# ifdef MSWIN
40 QueryPerformanceCounter(&now);
41 tm->QuadPart = now.QuadPart - tm->QuadPart;
42# else
Ernie Rael076de792023-03-16 21:43:15 +000043 PROF_GET_TIME(&now);
44 tm->tv_fsec = now.tv_fsec - tm->tv_fsec;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020045 tm->tv_sec = now.tv_sec - tm->tv_sec;
Ernie Rael076de792023-03-16 21:43:15 +000046 if (tm->tv_fsec < 0)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020047 {
Ernie Rael076de792023-03-16 21:43:15 +000048 tm->tv_fsec += TV_FSEC_SEC;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020049 --tm->tv_sec;
50 }
51# endif
52}
53
54/*
55 * Subtract the time "tm2" from "tm".
56 */
57 void
58profile_sub(proftime_T *tm, proftime_T *tm2)
59{
60# ifdef MSWIN
61 tm->QuadPart -= tm2->QuadPart;
62# else
Ernie Rael076de792023-03-16 21:43:15 +000063 tm->tv_fsec -= tm2->tv_fsec;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020064 tm->tv_sec -= tm2->tv_sec;
Ernie Rael076de792023-03-16 21:43:15 +000065 if (tm->tv_fsec < 0)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020066 {
Ernie Rael076de792023-03-16 21:43:15 +000067 tm->tv_fsec += TV_FSEC_SEC;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020068 --tm->tv_sec;
69 }
70# endif
71}
72
73/*
74 * Return a string that represents the time in "tm".
75 * Uses a static buffer!
76 */
77 char *
78profile_msg(proftime_T *tm)
79{
80 static char buf[50];
81
82# ifdef MSWIN
83 LARGE_INTEGER fr;
84
85 QueryPerformanceFrequency(&fr);
86 sprintf(buf, "%10.6lf", (double)tm->QuadPart / (double)fr.QuadPart);
87# else
Ernie Rael076de792023-03-16 21:43:15 +000088 sprintf(buf, PROF_TIME_FORMAT, (long)tm->tv_sec, (long)tm->tv_fsec);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020089# endif
90 return buf;
91}
92
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +020093/*
94 * Return a float that represents the time in "tm".
95 */
96 float_T
97profile_float(proftime_T *tm)
98{
Bram Moolenaar73e28dc2022-09-17 21:08:33 +010099# ifdef MSWIN
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200100 LARGE_INTEGER fr;
101
102 QueryPerformanceFrequency(&fr);
103 return (float_T)tm->QuadPart / (float_T)fr.QuadPart;
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100104# else
Ernie Rael076de792023-03-16 21:43:15 +0000105 return (float_T)tm->tv_sec + (float_T)tm->tv_fsec / (float_T)TV_FSEC_SEC;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200106# endif
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100107}
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200108
109/*
110 * Put the time "msec" past now in "tm".
111 */
112 void
113profile_setlimit(long msec, proftime_T *tm)
114{
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200115 if (msec <= 0) // no limit
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200116 profile_zero(tm);
117 else
118 {
119# ifdef MSWIN
120 LARGE_INTEGER fr;
121
122 QueryPerformanceCounter(tm);
123 QueryPerformanceFrequency(&fr);
124 tm->QuadPart += (LONGLONG)((double)msec / 1000.0 * (double)fr.QuadPart);
125# else
Isao Satod13c2542023-05-19 13:20:34 +0100126 varnumber_T fsec; // this should be 64 bit if possible
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200127
Ernie Rael076de792023-03-16 21:43:15 +0000128 PROF_GET_TIME(tm);
Isao Satod13c2542023-05-19 13:20:34 +0100129 fsec = (varnumber_T)tm->tv_fsec
130 + (varnumber_T)msec * (varnumber_T)(TV_FSEC_SEC / 1000);
Ernie Rael076de792023-03-16 21:43:15 +0000131 tm->tv_fsec = fsec % (long)TV_FSEC_SEC;
132 tm->tv_sec += fsec / (long)TV_FSEC_SEC;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200133# endif
134 }
135}
136
137/*
138 * Return TRUE if the current time is past "tm".
139 */
140 int
141profile_passed_limit(proftime_T *tm)
142{
143 proftime_T now;
144
145# ifdef MSWIN
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200146 if (tm->QuadPart == 0) // timer was not set
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200147 return FALSE;
148 QueryPerformanceCounter(&now);
149 return (now.QuadPart > tm->QuadPart);
150# else
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200151 if (tm->tv_sec == 0) // timer was not set
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200152 return FALSE;
Ernie Rael076de792023-03-16 21:43:15 +0000153 PROF_GET_TIME(&now);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200154 return (now.tv_sec > tm->tv_sec
Ernie Rael076de792023-03-16 21:43:15 +0000155 || (now.tv_sec == tm->tv_sec && now.tv_fsec > tm->tv_fsec));
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200156# endif
157}
158
159/*
160 * Set the time in "tm" to zero.
161 */
162 void
163profile_zero(proftime_T *tm)
164{
165# ifdef MSWIN
166 tm->QuadPart = 0;
167# else
Ernie Rael076de792023-03-16 21:43:15 +0000168 tm->tv_fsec = 0;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200169 tm->tv_sec = 0;
170# endif
171}
172
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200173# endif // FEAT_PROFILE || FEAT_RELTIME
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200174
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100175#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_PROFILE)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200176# if defined(HAVE_MATH_H)
177# include <math.h>
178# endif
179
180/*
181 * Divide the time "tm" by "count" and store in "tm2".
182 */
183 void
184profile_divide(proftime_T *tm, int count, proftime_T *tm2)
185{
186 if (count == 0)
187 profile_zero(tm2);
188 else
189 {
190# ifdef MSWIN
191 tm2->QuadPart = tm->QuadPart / count;
192# else
Ernie Rael076de792023-03-16 21:43:15 +0000193 double fsec = (tm->tv_sec * (float_T)TV_FSEC_SEC + tm->tv_fsec)
194 / count;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200195
Ernie Rael076de792023-03-16 21:43:15 +0000196 tm2->tv_sec = floor(fsec / (float_T)TV_FSEC_SEC);
197 tm2->tv_fsec = vim_round(fsec - (tm2->tv_sec * (float_T)TV_FSEC_SEC));
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200198# endif
199 }
200}
201#endif
202
203# if defined(FEAT_PROFILE) || defined(PROTO)
204/*
205 * Functions for profiling.
206 */
207static proftime_T prof_wait_time;
208
209/*
210 * Add the time "tm2" to "tm".
211 */
212 void
213profile_add(proftime_T *tm, proftime_T *tm2)
214{
215# ifdef MSWIN
216 tm->QuadPart += tm2->QuadPart;
217# else
Ernie Rael076de792023-03-16 21:43:15 +0000218 tm->tv_fsec += tm2->tv_fsec;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200219 tm->tv_sec += tm2->tv_sec;
Ernie Rael076de792023-03-16 21:43:15 +0000220 if (tm->tv_fsec >= TV_FSEC_SEC)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200221 {
Ernie Rael076de792023-03-16 21:43:15 +0000222 tm->tv_fsec -= TV_FSEC_SEC;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200223 ++tm->tv_sec;
224 }
225# endif
226}
227
228/*
229 * Add the "self" time from the total time and the children's time.
230 */
231 void
232profile_self(proftime_T *self, proftime_T *total, proftime_T *children)
233{
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200234 // Check that the result won't be negative. Can happen with recursive
235 // calls.
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200236#ifdef MSWIN
237 if (total->QuadPart <= children->QuadPart)
238 return;
239#else
240 if (total->tv_sec < children->tv_sec
241 || (total->tv_sec == children->tv_sec
Ernie Rael076de792023-03-16 21:43:15 +0000242 && total->tv_fsec <= children->tv_fsec))
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200243 return;
244#endif
245 profile_add(self, total);
246 profile_sub(self, children);
247}
248
249/*
250 * Get the current waittime.
251 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +0200252 static void
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200253profile_get_wait(proftime_T *tm)
254{
255 *tm = prof_wait_time;
256}
257
258/*
259 * Subtract the passed waittime since "tm" from "tma".
260 */
261 void
262profile_sub_wait(proftime_T *tm, proftime_T *tma)
263{
264 proftime_T tm3 = prof_wait_time;
265
266 profile_sub(&tm3, tm);
267 profile_sub(tma, &tm3);
268}
269
270/*
271 * Return TRUE if "tm1" and "tm2" are equal.
272 */
Bram Moolenaar5843f5f2019-08-20 20:13:45 +0200273 static int
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200274profile_equal(proftime_T *tm1, proftime_T *tm2)
275{
276# ifdef MSWIN
277 return (tm1->QuadPart == tm2->QuadPart);
278# else
Ernie Rael076de792023-03-16 21:43:15 +0000279 return (tm1->tv_fsec == tm2->tv_fsec && tm1->tv_sec == tm2->tv_sec);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200280# endif
281}
282
283/*
284 * Return <0, 0 or >0 if "tm1" < "tm2", "tm1" == "tm2" or "tm1" > "tm2"
285 */
286 int
287profile_cmp(const proftime_T *tm1, const proftime_T *tm2)
288{
289# ifdef MSWIN
Christian Brabandte06e4372024-02-09 19:39:14 +0100290 return tm2->QuadPart == tm1->QuadPart ? 0 :
291 tm2->QuadPart > tm1->QuadPart ? 1 : -1;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200292# else
293 if (tm1->tv_sec == tm2->tv_sec)
Christian Brabandte06e4372024-02-09 19:39:14 +0100294 return tm2->tv_fsec == tm1->tv_fsec ? 0 :
295 tm2->tv_fsec > tm1->tv_fsec ? 1 : -1;
296 return tm2->tv_sec > tm1->tv_sec ? 1 : -1;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200297# endif
298}
299
300static char_u *profile_fname = NULL;
301static proftime_T pause_time;
302
303/*
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100304 * Reset all profiling information.
305 */
306 static void
307profile_reset(void)
308{
309 int id;
310 int todo;
311 hashtab_T *functbl;
312 hashitem_T *hi;
313
314 // Reset sourced files.
315 for (id = 1; id <= script_items.ga_len; id++)
316 {
317 scriptitem_T *si = SCRIPT_ITEM(id);
318 if (si->sn_prof_on)
319 {
320 si->sn_prof_on = FALSE;
321 si->sn_pr_force = FALSE;
322 profile_zero(&si->sn_pr_child);
323 si->sn_pr_nest = 0;
324 si->sn_pr_count = 0;
325 profile_zero(&si->sn_pr_total);
326 profile_zero(&si->sn_pr_self);
327 profile_zero(&si->sn_pr_start);
328 profile_zero(&si->sn_pr_children);
329 ga_clear(&si->sn_prl_ga);
330 profile_zero(&si->sn_prl_start);
331 profile_zero(&si->sn_prl_children);
332 profile_zero(&si->sn_prl_wait);
333 si->sn_prl_idx = -1;
334 si->sn_prl_execed = 0;
335 }
336 }
337
338 // Reset functions.
339 functbl = func_tbl_get();
340 todo = (int)functbl->ht_used;
341
Yegappan Lakshmanan14113fd2023-03-07 17:13:51 +0000342 FOR_ALL_HASHTAB_ITEMS(functbl, hi, todo)
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100343 {
344 ufunc_T *fp;
345 int i;
346
347 if (HASHITEM_EMPTY(hi))
348 continue;
349
350 todo--;
351 fp = HI2UF(hi);
352 if (fp->uf_prof_initialized)
353 {
354 fp->uf_profiling = 0;
355 fp->uf_prof_initialized = FALSE;
356 fp->uf_tm_count = 0;
357 profile_zero(&fp->uf_tm_total);
358 profile_zero(&fp->uf_tm_self);
359 profile_zero(&fp->uf_tm_children);
360
361 for (i = 0; i < fp->uf_lines.ga_len; i++)
362 {
363 fp->uf_tml_count[i] = 0;
364 profile_zero(&fp->uf_tml_total[i]);
365 profile_zero(&fp->uf_tml_self[i]);
366 }
367
368 profile_zero(&fp->uf_tml_start);
369 profile_zero(&fp->uf_tml_children);
370 profile_zero(&fp->uf_tml_wait);
371 fp->uf_tml_idx = -1;
372 fp->uf_tml_execed = 0;
373 }
374 }
375
376 VIM_CLEAR(profile_fname);
377}
378
379/*
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200380 * ":profile cmd args"
381 */
382 void
383ex_profile(exarg_T *eap)
384{
385 char_u *e;
386 int len;
387
388 e = skiptowhite(eap->arg);
389 len = (int)(e - eap->arg);
390 e = skipwhite(e);
391
392 if (len == 5 && STRNCMP(eap->arg, "start", 5) == 0 && *e != NUL)
393 {
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100394 VIM_CLEAR(profile_fname);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200395 profile_fname = expand_env_save_opt(e, TRUE);
396 do_profiling = PROF_YES;
397 profile_zero(&prof_wait_time);
398 set_vim_var_nr(VV_PROFILING, 1L);
399 }
400 else if (do_profiling == PROF_NONE)
Bram Moolenaar677658a2022-01-05 16:09:06 +0000401 emsg(_(e_first_use_profile_start_fname));
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100402 else if (STRCMP(eap->arg, "stop") == 0)
403 {
404 profile_dump();
405 do_profiling = PROF_NONE;
406 set_vim_var_nr(VV_PROFILING, 0L);
407 profile_reset();
408 }
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200409 else if (STRCMP(eap->arg, "pause") == 0)
410 {
411 if (do_profiling == PROF_YES)
412 profile_start(&pause_time);
413 do_profiling = PROF_PAUSED;
414 }
415 else if (STRCMP(eap->arg, "continue") == 0)
416 {
417 if (do_profiling == PROF_PAUSED)
418 {
419 profile_end(&pause_time);
420 profile_add(&prof_wait_time, &pause_time);
421 }
422 do_profiling = PROF_YES;
423 }
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100424 else if (STRCMP(eap->arg, "dump") == 0)
425 profile_dump();
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200426 else
427 {
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200428 // The rest is similar to ":breakadd".
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200429 ex_breakadd(eap);
430 }
431}
432
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200433// Command line expansion for :profile.
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200434static enum
435{
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200436 PEXP_SUBCMD, // expand :profile sub-commands
437 PEXP_FUNC // expand :profile func {funcname}
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200438} pexpand_what;
439
440static char *pexpand_cmds[] = {
441 "start",
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100442 "stop",
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200443 "pause",
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200444 "continue",
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200445 "func",
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200446 "file",
Yegappan Lakshmanan18ee0f62022-04-08 13:23:19 +0100447 "dump",
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200448 NULL
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200449};
450
451/*
452 * Function given to ExpandGeneric() to obtain the profile command
453 * specific expansion.
454 */
455 char_u *
456get_profile_name(expand_T *xp UNUSED, int idx)
457{
458 switch (pexpand_what)
459 {
460 case PEXP_SUBCMD:
461 return (char_u *)pexpand_cmds[idx];
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200462 default:
463 return NULL;
464 }
465}
466
467/*
468 * Handle command line completion for :profile command.
469 */
470 void
471set_context_in_profile_cmd(expand_T *xp, char_u *arg)
472{
473 char_u *end_subcmd;
474
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200475 // Default: expand subcommands.
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200476 xp->xp_context = EXPAND_PROFILE;
477 pexpand_what = PEXP_SUBCMD;
478 xp->xp_pattern = arg;
479
480 end_subcmd = skiptowhite(arg);
481 if (*end_subcmd == NUL)
482 return;
483
Yegappan Lakshmanan1fdf84e2022-03-15 10:53:09 +0000484 if ((end_subcmd - arg == 5 && STRNCMP(arg, "start", 5) == 0)
485 || (end_subcmd - arg == 4 && STRNCMP(arg, "file", 4) == 0))
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200486 {
487 xp->xp_context = EXPAND_FILES;
488 xp->xp_pattern = skipwhite(end_subcmd);
489 return;
490 }
Yegappan Lakshmanan1fdf84e2022-03-15 10:53:09 +0000491 else if (end_subcmd - arg == 4 && STRNCMP(arg, "func", 4) == 0)
492 {
493 xp->xp_context = EXPAND_USER_FUNC;
494 xp->xp_pattern = skipwhite(end_subcmd);
495 return;
496 }
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200497
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200498 xp->xp_context = EXPAND_NOTHING;
499}
500
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200501static proftime_T inchar_time;
502
503/*
504 * Called when starting to wait for the user to type a character.
505 */
506 void
507prof_inchar_enter(void)
508{
509 profile_start(&inchar_time);
510}
511
512/*
513 * Called when finished waiting for the user to type a character.
514 */
515 void
516prof_inchar_exit(void)
517{
518 profile_end(&inchar_time);
519 profile_add(&prof_wait_time, &inchar_time);
520}
521
522
523/*
524 * Return TRUE when a function defined in the current script should be
525 * profiled.
526 */
527 int
528prof_def_func(void)
529{
530 if (current_sctx.sc_sid > 0)
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100531 return SCRIPT_ITEM(current_sctx.sc_sid)->sn_pr_force;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200532 return FALSE;
533}
534
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200535/*
536 * Print the count and times for one function or function line.
537 */
538 static void
539prof_func_line(
540 FILE *fd,
541 int count,
542 proftime_T *total,
543 proftime_T *self,
544 int prefer_self) // when equal print only self time
545{
546 if (count > 0)
547 {
548 fprintf(fd, "%5d ", count);
549 if (prefer_self && profile_equal(total, self))
Ernie Rael076de792023-03-16 21:43:15 +0000550 fprintf(fd, PROF_TIME_BLANK);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200551 else
552 fprintf(fd, "%s ", profile_msg(total));
553 if (!prefer_self && profile_equal(total, self))
Ernie Rael076de792023-03-16 21:43:15 +0000554 fprintf(fd, PROF_TIME_BLANK);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200555 else
556 fprintf(fd, "%s ", profile_msg(self));
557 }
558 else
Ernie Rael076de792023-03-16 21:43:15 +0000559 fprintf(fd, " %s%s", PROF_TIME_BLANK, PROF_TIME_BLANK);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200560}
561
562 static void
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200563prof_sort_list(
564 FILE *fd,
565 ufunc_T **sorttab,
566 int st_len,
567 char *title,
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200568 int prefer_self) // when equal print only self time
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200569{
570 int i;
571 ufunc_T *fp;
572
573 fprintf(fd, "FUNCTIONS SORTED ON %s TIME\n", title);
Ernie Rael076de792023-03-16 21:43:15 +0000574 fprintf(fd, "%s function\n", PROF_TOTALS_HEADER);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200575 for (i = 0; i < 20 && i < st_len; ++i)
576 {
577 fp = sorttab[i];
578 prof_func_line(fd, fp->uf_tm_count, &fp->uf_tm_total, &fp->uf_tm_self,
579 prefer_self);
580 if (fp->uf_name[0] == K_SPECIAL)
581 fprintf(fd, " <SNR>%s()\n", fp->uf_name + 3);
582 else
583 fprintf(fd, " %s()\n", fp->uf_name);
584 }
585 fprintf(fd, "\n");
586}
587
588/*
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200589 * Compare function for total time sorting.
590 */
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200591 static int
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200592prof_total_cmp(const void *s1, const void *s2)
593{
594 ufunc_T *p1, *p2;
595
596 p1 = *(ufunc_T **)s1;
597 p2 = *(ufunc_T **)s2;
598 return profile_cmp(&p1->uf_tm_total, &p2->uf_tm_total);
599}
600
601/*
602 * Compare function for self time sorting.
603 */
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200604 static int
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200605prof_self_cmp(const void *s1, const void *s2)
606{
607 ufunc_T *p1, *p2;
608
609 p1 = *(ufunc_T **)s1;
610 p2 = *(ufunc_T **)s2;
611 return profile_cmp(&p1->uf_tm_self, &p2->uf_tm_self);
612}
613
614/*
615 * Start profiling function "fp".
616 */
617 void
618func_do_profile(ufunc_T *fp)
619{
620 int len = fp->uf_lines.ga_len;
621
622 if (!fp->uf_prof_initialized)
623 {
624 if (len == 0)
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200625 len = 1; // avoid getting error for allocating zero bytes
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200626 fp->uf_tm_count = 0;
627 profile_zero(&fp->uf_tm_self);
628 profile_zero(&fp->uf_tm_total);
629 if (fp->uf_tml_count == NULL)
630 fp->uf_tml_count = ALLOC_CLEAR_MULT(int, len);
631 if (fp->uf_tml_total == NULL)
632 fp->uf_tml_total = ALLOC_CLEAR_MULT(proftime_T, len);
633 if (fp->uf_tml_self == NULL)
634 fp->uf_tml_self = ALLOC_CLEAR_MULT(proftime_T, len);
635 fp->uf_tml_idx = -1;
636 if (fp->uf_tml_count == NULL || fp->uf_tml_total == NULL
637 || fp->uf_tml_self == NULL)
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200638 return; // out of memory
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200639 fp->uf_prof_initialized = TRUE;
640 }
641
642 fp->uf_profiling = TRUE;
643}
644
645/*
Yegappan Lakshmanan8ee52af2021-08-09 19:59:06 +0200646 * Save time when starting to invoke another script or function.
647 */
648 static void
649script_prof_save(
650 proftime_T *tm) // place to store wait time
651{
652 scriptitem_T *si;
653
654 if (SCRIPT_ID_VALID(current_sctx.sc_sid))
655 {
656 si = SCRIPT_ITEM(current_sctx.sc_sid);
657 if (si->sn_prof_on && si->sn_pr_nest++ == 0)
658 profile_start(&si->sn_pr_child);
659 }
660 profile_get_wait(tm);
661}
662
663/*
Bram Moolenaarb2049902021-01-24 12:53:53 +0100664 * When calling a function: may initialize for profiling.
665 */
666 void
Bram Moolenaar12d26532021-02-19 19:13:21 +0100667profile_may_start_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller)
Bram Moolenaarb2049902021-01-24 12:53:53 +0100668{
Ernie Rael21d32122023-09-02 15:09:18 +0200669 if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL,
670 &fp->uf_hash))
Bram Moolenaarb2049902021-01-24 12:53:53 +0100671 {
Bram Moolenaar12d26532021-02-19 19:13:21 +0100672 info->pi_started_profiling = TRUE;
673 func_do_profile(fp);
Bram Moolenaarb2049902021-01-24 12:53:53 +0100674 }
Bram Moolenaar12d26532021-02-19 19:13:21 +0100675 if (fp->uf_profiling || (caller != NULL && caller->uf_profiling))
676 {
677 ++fp->uf_tm_count;
678 profile_start(&info->pi_call_start);
679 profile_zero(&fp->uf_tm_children);
680 }
681 script_prof_save(&info->pi_wait_start);
Bram Moolenaarb2049902021-01-24 12:53:53 +0100682}
683
684/*
685 * After calling a function: may handle profiling. profile_may_start_func()
686 * must have been called previously.
687 */
688 void
Bram Moolenaar12d26532021-02-19 19:13:21 +0100689profile_may_end_func(profinfo_T *info, ufunc_T *fp, ufunc_T *caller)
Bram Moolenaarb2049902021-01-24 12:53:53 +0100690{
691 profile_end(&info->pi_call_start);
692 profile_sub_wait(&info->pi_wait_start, &info->pi_call_start);
693 profile_add(&fp->uf_tm_total, &info->pi_call_start);
694 profile_self(&fp->uf_tm_self, &info->pi_call_start, &fp->uf_tm_children);
Bram Moolenaar12d26532021-02-19 19:13:21 +0100695 if (caller != NULL && caller->uf_profiling)
Bram Moolenaarb2049902021-01-24 12:53:53 +0100696 {
Bram Moolenaar12d26532021-02-19 19:13:21 +0100697 profile_add(&caller->uf_tm_children, &info->pi_call_start);
698 profile_add(&caller->uf_tml_children, &info->pi_call_start);
Bram Moolenaarb2049902021-01-24 12:53:53 +0100699 }
700 if (info->pi_started_profiling)
701 // make a ":profdel func" stop profiling the function
702 fp->uf_profiling = FALSE;
703}
704
705/*
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200706 * Prepare profiling for entering a child or something else that is not
707 * counted for the script/function itself.
708 * Should always be called in pair with prof_child_exit().
709 */
710 void
711prof_child_enter(
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200712 proftime_T *tm) // place to store waittime
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200713{
714 funccall_T *fc = get_current_funccal();
715
Bram Moolenaarca16c602022-09-06 18:57:08 +0100716 if (fc != NULL && fc->fc_func->uf_profiling)
717 profile_start(&fc->fc_prof_child);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200718 script_prof_save(tm);
719}
720
721/*
722 * Take care of time spent in a child.
723 * Should always be called after prof_child_enter().
724 */
725 void
726prof_child_exit(
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200727 proftime_T *tm) // where waittime was stored
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200728{
729 funccall_T *fc = get_current_funccal();
730
Bram Moolenaarca16c602022-09-06 18:57:08 +0100731 if (fc != NULL && fc->fc_func->uf_profiling)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200732 {
Bram Moolenaarca16c602022-09-06 18:57:08 +0100733 profile_end(&fc->fc_prof_child);
734 profile_sub_wait(tm, &fc->fc_prof_child); // don't count waiting time
735 profile_add(&fc->fc_func->uf_tm_children, &fc->fc_prof_child);
736 profile_add(&fc->fc_func->uf_tml_children, &fc->fc_prof_child);
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200737 }
738 script_prof_restore(tm);
739}
740
741/*
742 * Called when starting to read a function line.
743 * "sourcing_lnum" must be correct!
744 * When skipping lines it may not actually be executed, but we won't find out
745 * until later and we need to store the time now.
746 */
747 void
Bram Moolenaarb2049902021-01-24 12:53:53 +0100748func_line_start(void *cookie, long lnum)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200749{
750 funccall_T *fcp = (funccall_T *)cookie;
Bram Moolenaarca16c602022-09-06 18:57:08 +0100751 ufunc_T *fp = fcp->fc_func;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200752
Bram Moolenaarb2049902021-01-24 12:53:53 +0100753 if (fp->uf_profiling && lnum >= 1 && lnum <= fp->uf_lines.ga_len)
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200754 {
Bram Moolenaarb2049902021-01-24 12:53:53 +0100755 fp->uf_tml_idx = lnum - 1;
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200756 // Skip continuation lines.
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200757 while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)
758 --fp->uf_tml_idx;
759 fp->uf_tml_execed = FALSE;
760 profile_start(&fp->uf_tml_start);
761 profile_zero(&fp->uf_tml_children);
762 profile_get_wait(&fp->uf_tml_wait);
763 }
764}
765
766/*
767 * Called when actually executing a function line.
768 */
769 void
770func_line_exec(void *cookie)
771{
772 funccall_T *fcp = (funccall_T *)cookie;
Bram Moolenaarca16c602022-09-06 18:57:08 +0100773 ufunc_T *fp = fcp->fc_func;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200774
775 if (fp->uf_profiling && fp->uf_tml_idx >= 0)
776 fp->uf_tml_execed = TRUE;
777}
778
779/*
780 * Called when done with a function line.
781 */
782 void
783func_line_end(void *cookie)
784{
785 funccall_T *fcp = (funccall_T *)cookie;
Bram Moolenaarca16c602022-09-06 18:57:08 +0100786 ufunc_T *fp = fcp->fc_func;
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +0200787
788 if (fp->uf_profiling && fp->uf_tml_idx >= 0)
789 {
790 if (fp->uf_tml_execed)
791 {
792 ++fp->uf_tml_count[fp->uf_tml_idx];
793 profile_end(&fp->uf_tml_start);
794 profile_sub_wait(&fp->uf_tml_wait, &fp->uf_tml_start);
795 profile_add(&fp->uf_tml_total[fp->uf_tml_idx], &fp->uf_tml_start);
796 profile_self(&fp->uf_tml_self[fp->uf_tml_idx], &fp->uf_tml_start,
797 &fp->uf_tml_children);
798 }
799 fp->uf_tml_idx = -1;
800 }
801}
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200802
803/*
804 * Dump the profiling results for all functions in file "fd".
805 */
806 static void
807func_dump_profile(FILE *fd)
808{
809 hashtab_T *functbl;
810 hashitem_T *hi;
811 int todo;
812 ufunc_T *fp;
813 int i;
814 ufunc_T **sorttab;
815 int st_len = 0;
816 char_u *p;
817
818 functbl = func_tbl_get();
819 todo = (int)functbl->ht_used;
820 if (todo == 0)
821 return; // nothing to dump
822
823 sorttab = ALLOC_MULT(ufunc_T *, todo);
824
Yegappan Lakshmanan14113fd2023-03-07 17:13:51 +0000825 FOR_ALL_HASHTAB_ITEMS(functbl, hi, todo)
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200826 {
827 if (!HASHITEM_EMPTY(hi))
828 {
829 --todo;
830 fp = HI2UF(hi);
831 if (fp->uf_prof_initialized)
832 {
833 if (sorttab != NULL)
834 sorttab[st_len++] = fp;
835
836 if (fp->uf_name[0] == K_SPECIAL)
837 fprintf(fd, "FUNCTION <SNR>%s()\n", fp->uf_name + 3);
838 else
839 fprintf(fd, "FUNCTION %s()\n", fp->uf_name);
Bram Moolenaar16358802019-08-30 18:37:26 +0200840 if (fp->uf_script_ctx.sc_sid > 0)
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200841 {
Bram Moolenaar16358802019-08-30 18:37:26 +0200842 p = home_replace_save(NULL,
843 get_scriptname(fp->uf_script_ctx.sc_sid));
844 if (p != NULL)
845 {
Bram Moolenaar181d4f52019-09-18 22:04:56 +0200846 fprintf(fd, " Defined: %s:%ld\n",
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200847 p, (long)fp->uf_script_ctx.sc_lnum);
Bram Moolenaar16358802019-08-30 18:37:26 +0200848 vim_free(p);
849 }
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200850 }
851 if (fp->uf_tm_count == 1)
852 fprintf(fd, "Called 1 time\n");
853 else
854 fprintf(fd, "Called %d times\n", fp->uf_tm_count);
855 fprintf(fd, "Total time: %s\n", profile_msg(&fp->uf_tm_total));
856 fprintf(fd, " Self time: %s\n", profile_msg(&fp->uf_tm_self));
857 fprintf(fd, "\n");
Ernie Rael076de792023-03-16 21:43:15 +0000858 fprintf(fd, "%s\n", PROF_TOTALS_HEADER);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200859
860 for (i = 0; i < fp->uf_lines.ga_len; ++i)
861 {
862 if (FUNCLINE(fp, i) == NULL)
863 continue;
864 prof_func_line(fd, fp->uf_tml_count[i],
865 &fp->uf_tml_total[i], &fp->uf_tml_self[i], TRUE);
866 fprintf(fd, "%s\n", FUNCLINE(fp, i));
867 }
868 fprintf(fd, "\n");
869 }
870 }
871 }
872
873 if (sorttab != NULL && st_len > 0)
874 {
875 qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
876 prof_total_cmp);
877 prof_sort_list(fd, sorttab, st_len, "TOTAL", FALSE);
878 qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *),
879 prof_self_cmp);
880 prof_sort_list(fd, sorttab, st_len, "SELF", TRUE);
881 }
882
883 vim_free(sorttab);
884}
885
886/*
887 * Start profiling script "fp".
888 */
889 void
890script_do_profile(scriptitem_T *si)
891{
892 si->sn_pr_count = 0;
893 profile_zero(&si->sn_pr_total);
894 profile_zero(&si->sn_pr_self);
895
896 ga_init2(&si->sn_prl_ga, sizeof(sn_prl_T), 100);
897 si->sn_prl_idx = -1;
898 si->sn_prof_on = TRUE;
899 si->sn_pr_nest = 0;
900}
901
902/*
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200903 * Count time spent in children after invoking another script or function.
904 */
905 void
906script_prof_restore(proftime_T *tm)
907{
908 scriptitem_T *si;
909
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000910 if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
911 return;
912
913 si = SCRIPT_ITEM(current_sctx.sc_sid);
914 if (si->sn_prof_on && --si->sn_pr_nest == 0)
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200915 {
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +0000916 profile_end(&si->sn_pr_child);
917 profile_sub_wait(tm, &si->sn_pr_child); // don't count wait time
918 profile_add(&si->sn_pr_children, &si->sn_pr_child);
919 profile_add(&si->sn_prl_children, &si->sn_pr_child);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200920 }
921}
922
923/*
924 * Dump the profiling results for all scripts in file "fd".
925 */
926 static void
927script_dump_profile(FILE *fd)
928{
929 int id;
930 scriptitem_T *si;
931 int i;
932 FILE *sfd;
933 sn_prl_T *pp;
934
935 for (id = 1; id <= script_items.ga_len; ++id)
936 {
Bram Moolenaar21b9e972020-01-26 19:26:46 +0100937 si = SCRIPT_ITEM(id);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200938 if (si->sn_prof_on)
939 {
940 fprintf(fd, "SCRIPT %s\n", si->sn_name);
941 if (si->sn_pr_count == 1)
942 fprintf(fd, "Sourced 1 time\n");
943 else
944 fprintf(fd, "Sourced %d times\n", si->sn_pr_count);
945 fprintf(fd, "Total time: %s\n", profile_msg(&si->sn_pr_total));
946 fprintf(fd, " Self time: %s\n", profile_msg(&si->sn_pr_self));
947 fprintf(fd, "\n");
Ernie Rael076de792023-03-16 21:43:15 +0000948 fprintf(fd, "%s\n", PROF_TOTALS_HEADER);
Bram Moolenaar660a10a2019-07-14 15:48:38 +0200949
950 sfd = mch_fopen((char *)si->sn_name, "r");
951 if (sfd == NULL)
952 fprintf(fd, "Cannot open file!\n");
953 else
954 {
955 // Keep going till the end of file, so that trailing
956 // continuation lines are listed.
957 for (i = 0; ; ++i)
958 {
959 if (vim_fgets(IObuff, IOSIZE, sfd))
960 break;
961 // When a line has been truncated, append NL, taking care
962 // of multi-byte characters .
963 if (IObuff[IOSIZE - 2] != NUL && IObuff[IOSIZE - 2] != NL)
964 {
965 int n = IOSIZE - 2;
966
967 if (enc_utf8)
968 {
969 // Move to the first byte of this char.
970 // utf_head_off() doesn't work, because it checks
971 // for a truncated character.
972 while (n > 0 && (IObuff[n] & 0xc0) == 0x80)
973 --n;
974 }
975 else if (has_mbyte)
976 n -= mb_head_off(IObuff, IObuff + n);
977 IObuff[n] = NL;
978 IObuff[n + 1] = NUL;
979 }
980 if (i < si->sn_prl_ga.ga_len
981 && (pp = &PRL_ITEM(si, i))->snp_count > 0)
982 {
983 fprintf(fd, "%5d ", pp->snp_count);
984 if (profile_equal(&pp->sn_prl_total, &pp->sn_prl_self))
985 fprintf(fd, " ");
986 else
987 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_total));
988 fprintf(fd, "%s ", profile_msg(&pp->sn_prl_self));
989 }
990 else
991 fprintf(fd, " ");
992 fprintf(fd, "%s", IObuff);
993 }
994 fclose(sfd);
995 }
996 fprintf(fd, "\n");
997 }
998 }
999}
1000
1001/*
1002 * Dump the profiling info.
1003 */
1004 void
1005profile_dump(void)
1006{
1007 FILE *fd;
1008
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00001009 if (profile_fname == NULL)
1010 return;
1011
1012 fd = mch_fopen((char *)profile_fname, "w");
1013 if (fd == NULL)
1014 semsg(_(e_cant_open_file_str), profile_fname);
1015 else
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001016 {
Yegappan Lakshmananf97a2952023-01-18 18:17:48 +00001017 script_dump_profile(fd);
1018 func_dump_profile(fd);
1019 fclose(fd);
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001020 }
1021}
1022
1023/*
1024 * Called when starting to read a script line.
1025 * "sourcing_lnum" must be correct!
1026 * When skipping lines it may not actually be executed, but we won't find out
1027 * until later and we need to store the time now.
1028 */
1029 void
1030script_line_start(void)
1031{
1032 scriptitem_T *si;
1033 sn_prl_T *pp;
1034
Bram Moolenaare3d46852020-08-29 13:39:17 +02001035 if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001036 return;
Bram Moolenaar21b9e972020-01-26 19:26:46 +01001037 si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001038 if (si->sn_prof_on && SOURCING_LNUM >= 1)
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001039 {
1040 // Grow the array before starting the timer, so that the time spent
1041 // here isn't counted.
1042 (void)ga_grow(&si->sn_prl_ga,
Bram Moolenaar1a47ae32019-12-29 23:04:25 +01001043 (int)(SOURCING_LNUM - si->sn_prl_ga.ga_len));
1044 si->sn_prl_idx = SOURCING_LNUM - 1;
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001045 while (si->sn_prl_ga.ga_len <= si->sn_prl_idx
1046 && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen)
1047 {
1048 // Zero counters for a line that was not used before.
1049 pp = &PRL_ITEM(si, si->sn_prl_ga.ga_len);
1050 pp->snp_count = 0;
1051 profile_zero(&pp->sn_prl_total);
1052 profile_zero(&pp->sn_prl_self);
1053 ++si->sn_prl_ga.ga_len;
1054 }
1055 si->sn_prl_execed = FALSE;
1056 profile_start(&si->sn_prl_start);
1057 profile_zero(&si->sn_prl_children);
1058 profile_get_wait(&si->sn_prl_wait);
1059 }
1060}
1061
1062/*
1063 * Called when actually executing a function line.
1064 */
1065 void
1066script_line_exec(void)
1067{
1068 scriptitem_T *si;
1069
Bram Moolenaare3d46852020-08-29 13:39:17 +02001070 if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001071 return;
Bram Moolenaar21b9e972020-01-26 19:26:46 +01001072 si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001073 if (si->sn_prof_on && si->sn_prl_idx >= 0)
1074 si->sn_prl_execed = TRUE;
1075}
1076
1077/*
1078 * Called when done with a script line.
1079 */
1080 void
1081script_line_end(void)
1082{
1083 scriptitem_T *si;
1084 sn_prl_T *pp;
1085
Bram Moolenaare3d46852020-08-29 13:39:17 +02001086 if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001087 return;
Bram Moolenaar21b9e972020-01-26 19:26:46 +01001088 si = SCRIPT_ITEM(current_sctx.sc_sid);
Bram Moolenaar660a10a2019-07-14 15:48:38 +02001089 if (si->sn_prof_on && si->sn_prl_idx >= 0
1090 && si->sn_prl_idx < si->sn_prl_ga.ga_len)
1091 {
1092 if (si->sn_prl_execed)
1093 {
1094 pp = &PRL_ITEM(si, si->sn_prl_idx);
1095 ++pp->snp_count;
1096 profile_end(&si->sn_prl_start);
1097 profile_sub_wait(&si->sn_prl_wait, &si->sn_prl_start);
1098 profile_add(&pp->sn_prl_total, &si->sn_prl_start);
1099 profile_self(&pp->sn_prl_self, &si->sn_prl_start,
1100 &si->sn_prl_children);
1101 }
1102 si->sn_prl_idx = -1;
1103 }
1104}
1105# endif // FEAT_PROFILE
Bram Moolenaarfa55cfc2019-07-13 22:59:32 +02001106
1107#endif