]> www.fi.muni.cz Git - evince.git/blob - lib/ev-debug.c
Add debugging helpers
[evince.git] / lib / ev-debug.c
1 /*
2  *  Copyright (C) 2003 Marco Pesenti Gritti
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2, or (at your option)
7  *  any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  *  $Id$
19  */
20
21 #include "config.h"
22
23 #include "ev-debug.h"
24
25 #ifndef DISABLE_PROFILING
26
27 #include <glib/gbacktrace.h>
28 #include <string.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <execinfo.h>
33
34 static GHashTable *ev_profilers_hash = NULL;
35 static const char *ev_profile_modules = NULL;
36 static const char *ev_debug_break = NULL;
37
38 #endif
39
40 #ifndef DISABLE_LOGGING
41
42 static const char *ev_log_modules;
43
44 static void
45 log_module (const gchar *log_domain,
46             GLogLevelFlags log_level,
47             const gchar *message,
48             gpointer user_data)
49 {
50         gboolean should_log = FALSE;
51
52         if (!ev_log_modules) return;
53
54         if (strcmp (ev_log_modules, "all") != 0)
55         {
56                 char **modules;
57                 int i;
58
59                 modules = g_strsplit (ev_log_modules, ":", 100);
60
61                 for (i = 0; modules[i] != NULL; i++)
62                 {
63                         if (strstr (message, modules [i]) != NULL)
64                         {
65                                 should_log = TRUE;
66                                 break;
67                         }
68                 }
69
70                 g_strfreev (modules);
71         }
72         else
73         {
74                 should_log = TRUE;
75         }
76
77         if (should_log)
78         {
79                 g_print ("%s\n", message);
80         }
81 }
82
83 #define MAX_DEPTH 200
84
85 static void 
86 trap_handler (const char *log_domain,
87               GLogLevelFlags log_level,
88               const char *message,
89               gpointer user_data)
90 {
91         g_log_default_handler (log_domain, log_level, message, user_data);
92
93         if (ev_debug_break != NULL &&
94             (log_level & (G_LOG_LEVEL_WARNING |
95                           G_LOG_LEVEL_ERROR |
96                           G_LOG_LEVEL_CRITICAL |
97                           G_LOG_FLAG_FATAL)))
98         {
99                 if (strcmp (ev_debug_break, "stack") == 0)
100                 {
101                         void *array[MAX_DEPTH];
102                         size_t size;
103                         
104                         size = backtrace (array, MAX_DEPTH);
105                         backtrace_symbols_fd (array, size, 2);
106                 }
107                 else if (strcmp (ev_debug_break, "trap") == 0)
108                 {
109                         G_BREAKPOINT ();
110                 }
111                 else if (strcmp (ev_debug_break, "suspend") == 0)
112                 {
113                         g_print ("Suspending program; attach with the debugger.\n");
114
115                         raise (SIGSTOP);
116                 }
117         }
118 }
119
120 #endif
121
122 void
123 ev_debug_init (void)
124 {
125 #ifndef DISABLE_LOGGING
126         ev_log_modules = g_getenv ("EV_LOG_MODULES");
127         ev_debug_break = g_getenv ("EV_DEBUG_BREAK");
128
129         g_log_set_default_handler (trap_handler, NULL);
130
131         g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, log_module, NULL);
132
133 #endif
134 #ifndef DISABLE_PROFILING
135         ev_profile_modules = g_getenv ("EV_PROFILE_MODULES");
136 #endif
137 }
138
139 #ifndef DISABLE_PROFILING
140
141 static EvProfiler *
142 ev_profiler_new (const char *name, const char *module)
143 {
144         EvProfiler *profiler;
145
146         profiler = g_new0 (EvProfiler, 1);
147         profiler->timer = g_timer_new ();
148         profiler->name  = g_strdup (name);
149         profiler->module  = g_strdup (module);
150
151         g_timer_start (profiler->timer);
152
153         return profiler;
154 }
155
156 static gboolean
157 ev_should_profile (const char *module)
158 {
159         char **modules;
160         int i;
161         gboolean res = FALSE;
162
163         if (!ev_profile_modules) return FALSE;
164         if (strcmp (ev_profile_modules, "all") == 0) return TRUE;
165
166         modules = g_strsplit (ev_profile_modules, ":", 100);
167
168         for (i = 0; modules[i] != NULL; i++)
169         {
170                 if (strcmp (module, modules [i]) == 0)
171                 {
172                         res = TRUE;
173                         break;
174                 }
175         }
176
177         g_strfreev (modules);
178
179         return res;
180 }
181
182 static void
183 ev_profiler_dump (EvProfiler *profiler)
184 {
185         double seconds;
186
187         g_return_if_fail (profiler != NULL);
188
189         seconds = g_timer_elapsed (profiler->timer, NULL);
190
191         g_print ("[ %s ] %s %f s elapsed\n",
192                  profiler->module, profiler->name,
193                  seconds);
194 }
195
196 static void
197 ev_profiler_free (EvProfiler *profiler)
198 {
199         g_return_if_fail (profiler != NULL);
200
201         g_timer_destroy (profiler->timer);
202         g_free (profiler->name);
203         g_free (profiler->module);
204         g_free (profiler);
205 }
206
207 void
208 ev_profiler_start (const char *name, const char *module)
209 {
210         EvProfiler *profiler;
211
212         if (ev_profilers_hash == NULL)
213         {
214                 ev_profilers_hash =
215                         g_hash_table_new_full (g_str_hash, g_str_equal,
216                                                g_free, NULL);
217         }
218
219         if (!ev_should_profile (module)) return;
220
221         profiler = ev_profiler_new (name, module);
222
223         g_hash_table_insert (ev_profilers_hash, g_strdup (name), profiler);
224 }
225
226 void
227 ev_profiler_stop (const char *name)
228 {
229         EvProfiler *profiler;
230
231         profiler = g_hash_table_lookup (ev_profilers_hash, name);
232         if (profiler == NULL) return;
233         g_hash_table_remove (ev_profilers_hash, name);
234
235         ev_profiler_dump (profiler);
236         ev_profiler_free (profiler);
237 }
238
239 #endif