rework the verifier to prepare for loop cutting
[ajla.git] / profile.c
blob59d971f1cc483509df7b5984487a834973fc1241
1 /*
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
9 * version.
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/>.
19 #include "ajla.h"
21 #include "str.h"
22 #include "thread.h"
23 #include "util.h"
24 #include "os.h"
26 #include "profile.h"
28 uchar_efficient_t profiling = 0;
29 uchar_efficient_t profiling_escapes = 0;
31 struct profile_data {
32 const char *function_name;
33 profile_counter_t profiling_counter;
34 profile_counter_t call_counter;
37 static struct profile_data *pd;
38 static size_t pd_len;
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);
55 return retval;
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)
80 size_t i;
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);
86 mem_free(pd);
90 struct profile_escape_data {
91 const char *function_name;
92 profile_counter_t profiling_counter;
93 ip_t ip;
94 unsigned line;
95 code_t code;
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)
105 return;
106 pe.function_name = str_dup(function_name, -1, NULL);
107 pe.profiling_counter = profiling_counter;
108 pe.ip = ip;
109 pe.line = line;
110 pe.code = code;
111 array_add(struct profile_escape_data, &ped, &ped_len, pe);
114 static int profile_escape_cmp(const void *p1, const void *p2)
116 int r;
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);
122 if (r)
123 return r;
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 return 0;
131 static void profile_escape_print(void)
133 size_t i;
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);
139 mem_free(ped);
143 bool function_enable_profile(const char *option, size_t l)
145 if (!option)
146 profiling = profiling_escapes = 1;
147 else if (l == 8 && !strncmp(option, "function", l))
148 profiling = 1;
149 else if (l == 6 && !strncmp(option, "escape", l))
150 profiling_escapes = 1;
151 else
152 return false;
153 return true;
156 void profile_init(void)
158 if (profiling) {
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)
169 if (profiling) {
170 profile_print();
171 tls_done(ajla_time_t, profiler_time);
173 if (profiling_escapes) {
174 profile_escape_print();