2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
28 uchar_efficient_t profiling
= 0;
29 uchar_efficient_t profiling_escapes
= 0;
32 const char *function_name
;
33 profile_counter_t profiling_counter
;
34 profile_counter_t call_counter
;
37 static struct profile_data
*pd
;
40 tls_decl(ajla_time_t
, profiler_time
);
42 void profile_unblock(void)
44 ajla_time_t now
= os_time_monotonic();
45 tls_set(ajla_time_t
, profiler_time
, now
);
48 profile_counter_t
profile_sample(void)
50 profile_counter_t retval
;
51 ajla_time_t now
= os_time_monotonic();
52 ajla_time_t us
= tls_get(ajla_time_t
, profiler_time
);
53 retval
= ((now
- us
) + 500) / 1000;
54 tls_set(ajla_time_t
, profiler_time
, now
);
58 void profile_collect(const char *function_name
, profile_counter_t profiling_counter
, profile_counter_t call_counter
)
60 struct profile_data p
;
61 p
.function_name
= str_dup(function_name
, -1, NULL
);
62 p
.profiling_counter
= profiling_counter
;
63 p
.call_counter
= call_counter
;
64 array_add(struct profile_data
, &pd
, &pd_len
, p
);
67 static int profile_cmp(const void *p1
, const void *p2
)
69 const struct profile_data
*q1
= p1
;
70 const struct profile_data
*q2
= p2
;
71 if (q1
->profiling_counter
< q2
->profiling_counter
) return -1;
72 if (q1
->profiling_counter
> q2
->profiling_counter
) return 1;
73 if (q1
->call_counter
< q2
->call_counter
) return -1;
74 if (q1
->call_counter
> q2
->call_counter
) return 1;
75 return strcmp(q1
->function_name
, q2
->function_name
);
78 static void profile_print(void)
81 qsort(pd
, pd_len
, sizeof(struct profile_data
), profile_cmp
);
82 for (i
= 0; i
< pd_len
; i
++) {
83 debug("%-30s %"PRIuMAX
" %"PRIuMAX
"", pd
[i
].function_name
, (uintmax_t)pd
[i
].profiling_counter
, (uintmax_t)pd
[i
].call_counter
);
84 mem_free(pd
[i
].function_name
);
90 struct profile_escape_data
{
91 const char *function_name
;
92 profile_counter_t profiling_counter
;
95 unsigned short compile_line
;
98 static struct profile_escape_data
*ped
;
99 static size_t ped_len
;
101 void profile_escape_collect(const char *function_name
, profile_counter_t profiling_counter
, unsigned line
, code_t code
, unsigned short compile_line
)
103 struct profile_escape_data pe
;
104 if ((code
% OPCODE_MODE_MULT
) == OPCODE_CHECKPOINT
)
106 pe
.function_name
= str_dup(function_name
, -1, NULL
);
107 pe
.profiling_counter
= profiling_counter
;
110 pe
.compile_line
= compile_line
;
111 array_add(struct profile_escape_data
, &ped
, &ped_len
, pe
);
114 static int profile_escape_cmp(const void *p1
, const void *p2
)
117 const struct profile_escape_data
*q1
= p1
;
118 const struct profile_escape_data
*q2
= p2
;
119 if (q1
->profiling_counter
< q2
->profiling_counter
) return -1;
120 if (q1
->profiling_counter
> q2
->profiling_counter
) return 1;
121 r
= strcmp(q1
->function_name
, q2
->function_name
);
124 if (q1
->line
< q2
->line
) return -1;
125 if (q1
->line
> q2
->line
) return 1;
126 if (q1
->code
< q2
->code
) return -1;
127 if (q1
->code
> q2
->code
) return 1;
128 if (q1
->compile_line
< q2
->compile_line
) return -1;
129 if (q1
->compile_line
> q2
->compile_line
) return 1;
133 static void profile_escape_print(void)
136 qsort(ped
, ped_len
, sizeof(struct profile_escape_data
), profile_escape_cmp
);
137 for (i
= 0; i
< ped_len
; i
++) {
138 debug("%30s:%-6u %-10"PRIuMAX
" %s,%u", ped
[i
].function_name
, ped
[i
].line
, (uintmax_t)ped
[i
].profiling_counter
, decode_opcode(ped
[i
].code
, false), ped
[i
].compile_line
);
139 mem_free(ped
[i
].function_name
);
145 bool function_enable_profile(const char *option
, size_t l
)
148 profiling
= profiling_escapes
= 1;
149 else if (l
== 8 && !strncmp(option
, "function", l
))
151 else if (l
== 6 && !strncmp(option
, "escape", l
))
152 profiling_escapes
= 1;
158 void profile_init(void)
161 tls_init(ajla_time_t
, profiler_time
);
162 array_init(struct profile_data
, &pd
, &pd_len
);
164 if (profiling_escapes
) {
165 array_init(struct profile_escape_data
, &ped
, &ped_len
);
169 void profile_done(void)
173 tls_done(ajla_time_t
, profiler_time
);
175 if (profiling_escapes
) {
176 profile_escape_print();