1 /**************************************************************************
2 *
3 * Copyright (C) 2019 Chromium.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include "virgl_util.h"
30
31 #include <errno.h>
32 #ifdef HAVE_EVENTFD_H
33 #include <sys/eventfd.h>
34 #endif
35 #include <unistd.h>
36
37 #include "util/os_misc.h"
38 #include "util/u_pointer.h"
39
40 #include <assert.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #if ENABLE_TRACING == TRACE_WITH_PERFETTO
49 #include <vperfetto-min.h>
50 #endif
51
52 #if ENABLE_TRACING == TRACE_WITH_STDERR
53 #include <stdio.h>
54 #endif
55
hash_func_u32(const void * key)56 uint32_t hash_func_u32(const void *key)
57 {
58 intptr_t ip = pointer_to_intptr(key);
59 return (uint32_t)(ip & 0xffffffff);
60 }
61
equal_func(const void * key1,const void * key2)62 bool equal_func(const void *key1, const void *key2)
63 {
64 return key1 == key2;
65 }
66
has_eventfd(void)67 bool has_eventfd(void)
68 {
69 #ifdef HAVE_EVENTFD_H
70 return true;
71 #else
72 return false;
73 #endif
74 }
75
create_eventfd(unsigned int initval)76 int create_eventfd(unsigned int initval)
77 {
78 #ifdef HAVE_EVENTFD_H
79 return eventfd(initval, EFD_CLOEXEC | EFD_NONBLOCK);
80 #else
81 (void)initval;
82 return -1;
83 #endif
84 }
85
write_eventfd(int fd,uint64_t val)86 int write_eventfd(int fd, uint64_t val)
87 {
88 const char *buf = (const char *)&val;
89 size_t count = sizeof(val);
90 ssize_t ret = 0;
91
92 while (count) {
93 ret = write(fd, buf, count);
94 if (ret < 0) {
95 if (errno == EINTR)
96 continue;
97 break;
98 }
99 count -= ret;
100 buf += ret;
101 }
102
103 return count ? -1 : 0;
104 }
105
flush_eventfd(int fd)106 void flush_eventfd(int fd)
107 {
108 ssize_t len;
109 uint64_t value;
110 do {
111 len = read(fd, &value, sizeof(value));
112 } while ((len == -1 && errno == EINTR) || len == sizeof(value));
113 }
114
115 static
virgl_default_logger(const char * fmt,va_list va)116 void virgl_default_logger(const char *fmt, va_list va)
117 {
118 static FILE* fp = NULL;
119 if (NULL == fp) {
120 const char* log = getenv("VIRGL_LOG_FILE");
121 if (log) {
122 char *log_prefix = strdup(log);
123 char *log_suffix = strstr(log_prefix, "%PID%");
124 if (log_suffix) {
125 *log_suffix = 0;
126 log_suffix += 5;
127 int len = strlen(log) + 32;
128 char *name = malloc(len);
129 snprintf(name, len, "%s%d%s", log_prefix, getpid(), log_suffix);
130 fp = fopen(name, "a");
131 free(name);
132 } else {
133 fp = fopen(log, "a");
134 }
135 free(log_prefix);
136 if (NULL == fp) {
137 fprintf(stderr, "Can't open %s\n", log);
138 fp = stderr;
139 }
140 } else {
141 fp = stderr;
142 }
143 }
144 vfprintf(fp, fmt, va);
145 fflush(fp);
146 }
147
148 static
virgl_null_logger(UNUSED const char * fmt,UNUSED va_list va)149 void virgl_null_logger(UNUSED const char *fmt, UNUSED va_list va)
150 {
151 }
152
153 static virgl_debug_callback_type virgl_logger = virgl_default_logger;
154
virgl_log_set_logger(virgl_debug_callback_type logger)155 virgl_debug_callback_type virgl_log_set_logger(virgl_debug_callback_type logger)
156 {
157 virgl_debug_callback_type old = virgl_logger;
158
159 /* virgl_null_logger is internal */
160 if (old == virgl_null_logger)
161 old = NULL;
162 if (!logger)
163 logger = virgl_null_logger;
164
165 virgl_logger = logger;
166 return old;
167 }
168
virgl_logv(const char * fmt,va_list va)169 void virgl_logv(const char *fmt, va_list va)
170 {
171 assert(virgl_logger);
172 virgl_logger(fmt, va);
173 }
174
175 #if ENABLE_TRACING == TRACE_WITH_PERCETTO
PERCETTO_CATEGORY_DEFINE(VIRGL_PERCETTO_CATEGORIES)176 PERCETTO_CATEGORY_DEFINE(VIRGL_PERCETTO_CATEGORIES)
177
178 void trace_init(void)
179 {
180 PERCETTO_INIT(PERCETTO_CLOCK_DONT_CARE);
181 }
182 #endif
183
184 #if ENABLE_TRACING == TRACE_WITH_PERFETTO
on_tracing_state_change(bool enabled)185 static void on_tracing_state_change(bool enabled) {
186 virgl_log("%s: tracing state change: %d\n", __func__, enabled);
187 }
188
trace_init(void)189 void trace_init(void)
190 {
191 struct vperfetto_min_config config = {
192 .on_tracing_state_change = on_tracing_state_change,
193 .init_flags = VPERFETTO_INIT_FLAG_USE_SYSTEM_BACKEND,
194 .filename = NULL,
195 .shmem_size_hint_kb = 32 * 1024,
196 };
197
198 vperfetto_min_startTracing(&config);
199 }
200
trace_begin(const char * scope)201 const char *trace_begin(const char *scope)
202 {
203 vperfetto_min_beginTrackEvent_VMM(scope);
204 return scope;
205 }
206
trace_end(const char ** dummy)207 void trace_end(const char **dummy)
208 {
209 (void)dummy;
210 vperfetto_min_endTrackEvent_VMM();
211 }
212 #endif
213
214 #if ENABLE_TRACING == TRACE_WITH_STDERR
215 static int nesting_depth = 0;
trace_init(void)216 void trace_init(void)
217 {
218 }
219
trace_begin(const char * scope)220 const char *trace_begin(const char *scope)
221 {
222 for (int i = 0; i < nesting_depth; ++i)
223 fprintf(stderr, " ");
224
225 fprintf(stderr, "ENTER:%s\n", scope);
226 nesting_depth++;
227
228 return scope;
229 }
230
trace_end(const char ** func_name)231 void trace_end(const char **func_name)
232 {
233 --nesting_depth;
234 for (int i = 0; i < nesting_depth; ++i)
235 fprintf(stderr, " ");
236 fprintf(stderr, "LEAVE %s\n", *func_name);
237 }
238 #endif
239