trace: rework alloc tracing
[platform/upstream/gstreamer.git] / gst / gsttrace.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gsttrace.c: Tracing functions (deprecated)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /**
24  * SECTION:gsttrace
25  * @short_description: Tracing functionality
26  *
27  * Traces allows to track object allocation. They provide a instance counter per
28  * #GType. The counter is incremented for each object allocated and decremented
29  * it when it's freed.
30  *
31  * <example>
32  * <title>Tracing object instances</title>
33  *   <programlisting>
34  *     // trace un-freed object instances
35  *     gst_alloc_trace_set_flags_all (GST_ALLOC_TRACE_LIVE);
36  *     if (!gst_alloc_trace_available ()) {
37  *       g_warning ("Trace not available (recompile with trace enabled).");
38  *     }
39  *     gst_alloc_trace_print_live ();
40  *     // do something here
41  *     gst_alloc_trace_print_live ();
42  *   </programlisting>
43  * </example>
44  *
45  * Last reviewed on 2005-11-21 (0.9.5)
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51 #include <stdio.h>
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif
55 #include <sys/stat.h>
56 #include <fcntl.h>
57 #include <string.h>
58 #include <errno.h>
59
60 #if defined (_MSC_VER) && _MSC_VER >= 1400
61 # include <io.h>
62 #endif
63
64 #include "gst_private.h"
65 #include "gstinfo.h"
66
67 #include "gsttrace.h"
68
69 GMutex _gst_trace_mutex;
70
71 /* global flags */
72 static GstAllocTraceFlags _gst_trace_flags = GST_ALLOC_TRACE_NONE;
73
74 /* list of registered tracers */
75 static GList *_gst_alloc_tracers = NULL;
76
77 static void
78 _at_exit (void)
79 {
80   if (_gst_trace_flags)
81     _priv_gst_alloc_trace_dump ();
82 }
83
84 void
85 _priv_gst_alloc_trace_initialize (void)
86 {
87   const gchar *trace;
88
89   trace = g_getenv ("GST_TRACE");
90   if (trace != NULL) {
91     _gst_trace_flags = atoi (trace);
92     atexit (_at_exit);
93   }
94
95   g_mutex_init (&_gst_trace_mutex);
96 }
97
98 void
99 _priv_gst_alloc_trace_deinit (void)
100 {
101   g_mutex_clear (&_gst_trace_mutex);
102 }
103
104 /**
105  * _priv_gst_alloc_trace_register:
106  * @name: the name of the new alloc trace object.
107  * @offset: the offset in the object where a GType an be found. -1 when the
108  * object has no gtype.
109  *
110  * Register an get a handle to a GstAllocTrace object that
111  * can be used to trace memory allocations.
112  *
113  * Returns: A handle to a GstAllocTrace.
114  */
115 GstAllocTrace *
116 _priv_gst_alloc_trace_register (const gchar * name, goffset offset)
117 {
118   GstAllocTrace *trace;
119
120   g_return_val_if_fail (name, NULL);
121
122   trace = g_slice_new (GstAllocTrace);
123   trace->name = g_strdup (name);
124   trace->live = 0;
125   trace->mem_live = NULL;
126   trace->flags = _gst_trace_flags;
127   trace->offset = offset;
128
129   _gst_alloc_tracers = g_list_prepend (_gst_alloc_tracers, trace);
130
131   return trace;
132 }
133
134 static gint
135 compare_func (GstAllocTrace * a, GstAllocTrace * b)
136 {
137   return strcmp (a->name, b->name);
138 }
139
140 static GList *
141 gst_alloc_trace_list_sorted (void)
142 {
143   GList *ret;
144
145   ret = g_list_sort (g_list_copy (_gst_alloc_tracers),
146       (GCompareFunc) compare_func);
147
148   return ret;
149 }
150
151 static void
152 gst_alloc_trace_print (const GstAllocTrace * trace)
153 {
154   GSList *mem_live;
155
156   g_return_if_fail (trace != NULL);
157
158   if (trace->flags & GST_ALLOC_TRACE_LIVE) {
159     g_print ("%-22.22s : %d\n", trace->name, trace->live);
160   } else {
161     g_print ("%-22.22s : (no live count)\n", trace->name);
162   }
163
164   if (trace->flags & GST_ALLOC_TRACE_MEM_LIVE) {
165     mem_live = trace->mem_live;
166
167     while (mem_live) {
168       gpointer data = mem_live->data;
169       const gchar *type_name;
170
171       if (G_IS_OBJECT (data)) {
172         type_name = G_OBJECT_TYPE_NAME (data);
173       } else if (trace->offset != -1) {
174         GType type;
175
176         type = G_STRUCT_MEMBER (GType, data, trace->offset);
177         type_name = g_type_name (type);
178       } else {
179         type_name = "";
180       }
181
182       g_print ("  %-20.20s : %p\n", type_name, data);
183
184       mem_live = mem_live->next;
185     }
186   }
187 }
188
189 /**
190  * _priv_gst_alloc_trace_dump:
191  *
192  * Print the status of all registered alloc trace objects.
193  */
194 void
195 _priv_gst_alloc_trace_dump (void)
196 {
197   GList *orig, *walk;
198
199   orig = walk = gst_alloc_trace_list_sorted ();
200
201   while (walk) {
202     GstAllocTrace *trace = (GstAllocTrace *) walk->data;
203
204     gst_alloc_trace_print (trace);
205
206     walk = g_list_next (walk);
207   }
208
209   g_list_free (orig);
210 }