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
;
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
, ip_t ip
, unsigned line
, code_t code
)
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
;
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;
131 static void profile_escape_print(void)
134 qsort(ped
, ped_len
, sizeof(struct profile_escape_data
), profile_escape_cmp
);
135 for (i
= 0; i
< ped_len
; i
++) {
136 debug("%30s:%-6u %-10"PRIuMAX
" %s,%lx", ped
[i
].function_name
, ped
[i
].line
, (uintmax_t)ped
[i
].profiling_counter
, decode_opcode(ped
[i
].code
, false), (unsigned long)ped
[i
].ip
);
137 mem_free(ped
[i
].function_name
);
143 bool function_enable_profile(const char *option
, size_t l
)
146 profiling
= profiling_escapes
= 1;
147 else if (l
== 8 && !strncmp(option
, "function", l
))
149 else if (l
== 6 && !strncmp(option
, "escape", l
))
150 profiling_escapes
= 1;
156 void profile_init(void)
159 tls_init(ajla_time_t
, profiler_time
);
160 array_init(struct profile_data
, &pd
, &pd_len
);
162 if (profiling_escapes
) {
163 array_init(struct profile_escape_data
, &ped
, &ped_len
);
167 void profile_done(void)
171 tls_done(ajla_time_t
, profiler_time
);
173 if (profiling_escapes
) {
174 profile_escape_print();