Fix a Gtk warning when checking path input in the log viewer.
[anjuta-git-plugin.git] / plugins / profiler / gprof-call-graph.c
blob2814dbb3495009aeef5b1521197fbc8fefaca036
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * gprof-call-graph.c
4 * Copyright (C) James Liggett 2006 <jrliggett@cox.net>
5 *
6 * gprof-call-graph.c is free software.
7 *
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2, or (at your option) any later version.
12 * plugin.c 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.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with plugin.c. See the file "COPYING". If not,
19 * write to: The Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
24 #include "gprof-call-graph.h"
26 #define BLOCK_SEPARATOR "-----------------------------------------------"
28 struct _GProfCallGraphPriv
30 GList *blocks; /* Straight list of all call graph blocks */
31 GList *root; /* List of strings that refer to
32 * "root functions," or functions without
33 * parents. */
34 GHashTable *lookup_table; /* Find function blocks by name */
37 static void
38 gprof_call_graph_init (GProfCallGraph *self)
40 self->priv = g_new0 (GProfCallGraphPriv, 1);
42 self->priv->lookup_table = g_hash_table_new (g_str_hash, g_str_equal);
45 static void
46 gprof_call_graph_finalize (GObject *obj)
48 GProfCallGraph *self;
49 GList *current;
51 self = (GProfCallGraph *) obj;
53 g_hash_table_destroy (self->priv->lookup_table);
55 current = self->priv->blocks;
57 while (current)
59 gprof_call_graph_block_free (GPROF_CALL_GRAPH_BLOCK (current->data));
60 current = g_list_next (current);
63 g_list_free (self->priv->blocks);
64 g_list_free (self->priv->root);
66 g_free (self->priv);
69 static void
70 gprof_call_graph_class_init (GProfCallGraphClass *klass)
72 GObjectClass *object_class;
74 object_class = (GObjectClass *) klass;
76 object_class->finalize = gprof_call_graph_finalize;
79 static gchar **
80 get_primary_line_fields(gchar *buffer)
82 gchar **string_table;
83 gchar *line; /* line data without leading index number */
84 gchar *calls_field; /* Pointer to string that begins at the calls field */
85 gint i;
86 gint pos; /* Where are we in the buffer? */
88 string_table = g_new0 (gchar *, 6); /* NULL terminated */
90 /* Skip over index number */
91 line = strchr (buffer, ']') + 1;
93 /* Read the first 3 fields */
94 pos = 0;
96 for (i = 0; i < 3; i++)
97 string_table[i] = read_to_whitespace (&line[pos], &pos, pos);
99 /* In some cases, uncalled functions will have empty calls field */
100 calls_field = strip_whitespace (&line[pos]);
102 /* If the field begins with a number, we have the field. Otherwise,
103 * calls_field points to the function name. */
105 /* In some cases, index numbers at the end of lines will be in parenthesis
106 * instead of square brackets. */
108 if (g_ascii_isdigit(calls_field[0]))
110 string_table[3] = read_to_whitespace (&line[pos], &pos, pos);
111 string_table[4] = read_to_delimiter (&line[pos], " [");
113 if (!string_table[4])
114 string_table[4] = read_to_delimiter (&line[pos], " (");
116 else
118 string_table[3] = g_strdup ("0");
119 string_table[4] = read_to_delimiter (calls_field, " [");
121 if (!string_table[4])
122 string_table[4] = read_to_delimiter (calls_field, " (");
125 g_free (calls_field);
127 return string_table;
130 static gchar **
131 get_secondary_line_fields(gchar *buffer)
133 gchar **string_table;
134 gchar *line; /* Pointer to the beginning of the current field */
135 gint num_fields; /* Number of fields read from line */
136 gint pos;
137 gint i;
139 /* Secondary lines can have a maximum of 4 fields. In some cases (as in
140 * recursive functions) lines may have only 2. Continue to read
141 * fields until we encounter one that doesn't begin with a digit. This
142 * tells us that we've reached the last field in the line. */
144 string_table = g_new0 (gchar *, 5); /* NULL terminated */
146 num_fields = 0;
147 pos = 0;
148 line = strip_whitespace (buffer);
150 while (g_ascii_isdigit(line[0]))
152 string_table[num_fields] = read_to_whitespace (&buffer[pos], &pos, pos);
153 g_free (line);
154 line = strip_whitespace (&buffer[pos]);
155 num_fields++;
158 g_free (line);
160 /* If we only read one field, it refers to the calls field. If we didn't
161 * read any fields here, this tells us that the primary line that this
162 * line belongs to refers to an uncalled function */
164 if (num_fields == 1)
166 string_table[2] = string_table[0];
168 for (i = 0; i < 2; i++)
169 string_table[i] = g_strdup ("0");
171 else if (num_fields == 0)
173 g_free (string_table);
174 return NULL;
177 /* In some cases, index numbers at the end of lines will be in parenthesis
178 * instead of square brackets. */
179 string_table[3] = read_to_delimiter (&buffer[pos], " [");
181 if (!string_table[3])
182 string_table[3] = read_to_delimiter (&buffer[pos], " (");
184 return string_table;
187 static void
188 gprof_call_graph_add_block (GProfCallGraph *self, GProfCallGraphBlock *block)
190 GProfCallGraphBlockEntry *entry;
191 gchar *name;
193 entry = gprof_call_graph_block_get_primary_entry (block);
194 name = gprof_call_graph_block_entry_get_name (entry);
196 self->priv->blocks = g_list_append (self->priv->blocks, block);
197 g_hash_table_insert (self->priv->lookup_table, name, block);
199 if (!gprof_call_graph_block_has_parents (block))
200 self->priv->root = g_list_append (self->priv->root, block);
203 GType
204 gprof_call_graph_get_type (void)
206 static GType obj_type = 0;
208 if (!obj_type)
210 static const GTypeInfo obj_info =
212 sizeof (GProfCallGraphClass),
213 (GBaseInitFunc) NULL,
214 (GBaseFinalizeFunc) NULL,
215 (GClassInitFunc) gprof_call_graph_class_init,
216 (GClassFinalizeFunc) NULL,
217 NULL, /* class_data */
218 sizeof (GProfCallGraph),
219 0, /* n_preallocs */
220 (GInstanceInitFunc) gprof_call_graph_init,
221 NULL /* value_table */
223 obj_type = g_type_register_static (G_TYPE_OBJECT,
224 "GProfCallGraph", &obj_info,
227 return obj_type;
230 GProfCallGraph *
231 gprof_call_graph_new (FILE *stream, GProfFlatProfile *flat_profile)
233 gchar buffer[PATH_MAX];
234 gchar **fields;
235 size_t length;
236 GProfCallGraphBlock *block;
237 GProfCallGraphBlockEntry *entry;
238 gchar *entry_name;
239 GProfCallGraph *call_graph;
240 gboolean found_primary = FALSE;
242 call_graph = g_object_new (GPROF_CALL_GRAPH_TYPE, NULL);
244 /* Find the beginning of the call graph. The call graph begins with
245 * "index" */
248 /* Don't loop infinitely if we don't have any data */
249 if (!fgets (buffer, PATH_MAX, stream))
250 return call_graph;
252 } while (strncmp ("index", buffer, 5) != 0);
254 block = NULL;
256 while (fgets (buffer, PATH_MAX, stream))
258 /* If the first character of the line is 12, that's the end of the call
259 * graph. */
260 if (buffer[0] == 12)
261 break;
263 if (!block)
265 block = gprof_call_graph_block_new ();
266 found_primary = FALSE;
269 /* Remove the newline from the buffer */
270 length = strlen (buffer);
271 buffer[length - 1] = 0;
273 /* If we encounter the block separator, add the block to the graph */
274 if (strcmp (BLOCK_SEPARATOR, buffer) == 0)
276 gprof_call_graph_add_block (call_graph, block);
277 block = NULL;
279 else
281 /* If the buffer begins with an index number, treat it as a primary
282 * line */
283 if (buffer[0] == '[')
285 found_primary = TRUE;
287 fields = get_primary_line_fields (buffer);
288 entry = gprof_call_graph_block_primary_entry_new (fields);
290 g_strfreev (fields);
292 gprof_call_graph_block_add_primary_entry (block, entry);
294 else
296 fields = get_secondary_line_fields (buffer);
298 /* If we don't get any fields, that means this is a
299 * placeholder line.*/
300 if (!fields)
301 continue;
303 entry = gprof_call_graph_block_secondary_entry_new (fields);
304 entry_name = gprof_call_graph_block_entry_get_name (entry);
306 g_strfreev (fields);
308 if (gprof_flat_profile_find_entry(flat_profile, entry_name))
310 if (found_primary)
311 gprof_call_graph_block_add_child_entry (block, entry);
312 else
313 gprof_call_graph_block_add_parent_entry (block, entry);
315 else
316 gprof_call_graph_block_entry_free (entry);
321 return call_graph;
324 void
325 gprof_call_graph_free (GProfCallGraph *self)
327 g_object_unref (self);
330 GProfCallGraphBlock *
331 gprof_call_graph_find_block (GProfCallGraph *self, gchar *name)
333 return GPROF_CALL_GRAPH_BLOCK (g_hash_table_lookup (self->priv->lookup_table,
334 name));
337 GProfCallGraphBlock *
338 gprof_call_graph_get_first_block (GProfCallGraph *self, GList **iter)
340 *iter = self->priv->blocks;
342 if (*iter)
343 return GPROF_CALL_GRAPH_BLOCK ((*iter)->data);
344 else
345 return NULL;
348 GProfCallGraphBlock *
349 gprof_call_graph_get_root (GProfCallGraph *self, GList **iter)
351 *iter = self->priv->root;
353 if (*iter)
354 return GPROF_CALL_GRAPH_BLOCK ((*iter)->data);
355 else
356 return NULL;
359 void
360 gprof_call_graph_dump (GProfCallGraph *self, FILE *stream)
362 GProfCallGraphBlockEntry *function;
363 GProfCallGraphBlockEntry *current_parent;
364 GProfCallGraphBlockEntry *current_child;
365 GList *current_block;
366 GList *current_child_iter;
367 GList *current_parent_iter;
369 current_block = self->priv->blocks;
371 while (current_block)
373 function = gprof_call_graph_block_get_primary_entry (current_block->data);
375 fprintf (stream, "Function: %s\n",
376 gprof_call_graph_block_entry_get_name (function));
377 fprintf (stream, "Time: %0.2f\n",
378 gprof_call_graph_block_entry_get_time_perc (function));
379 fprintf (stream, "Self sec: %0.2f\n",
380 gprof_call_graph_block_entry_get_self_sec (function));
381 fprintf (stream, "Child sec: %0.2f\n",
382 gprof_call_graph_block_entry_get_child_sec (function));
383 fprintf (stream, "Calls: %s\n",
384 gprof_call_graph_block_entry_get_calls (function));
385 fprintf (stream, "Recursive: %s\n\n",
386 gprof_call_graph_block_is_recursive (current_block->data) ? "Yes" : "No");
388 fprintf (stream, "Called: \n");
390 current_child = gprof_call_graph_block_get_first_child (current_block->data,
391 &current_child_iter);
393 while (current_child)
395 fprintf (stream, "%s %0.2f, %0.2f, %0.2f, %s\n",
396 gprof_call_graph_block_entry_get_name (current_child),
397 gprof_call_graph_block_entry_get_time_perc (current_child),
398 gprof_call_graph_block_entry_get_self_sec (current_child),
399 gprof_call_graph_block_entry_get_child_sec (current_child),
400 gprof_call_graph_block_entry_get_calls (current_child));
402 current_child = gprof_call_graph_block_entry_get_next (current_child_iter,
403 &current_child_iter);
405 fprintf (stream, "\n");
407 fprintf (stream, "Called by: \n");
409 current_parent = gprof_call_graph_block_get_first_parent (current_block->data,
410 &current_parent_iter);
411 while (current_parent)
413 fprintf (stream, "%s %0.2f, %0.2f, %0.2f, %s\n",
414 gprof_call_graph_block_entry_get_name (current_parent),
415 gprof_call_graph_block_entry_get_time_perc (current_parent),
416 gprof_call_graph_block_entry_get_self_sec (current_parent),
417 gprof_call_graph_block_entry_get_child_sec (current_parent),
418 gprof_call_graph_block_entry_get_calls (current_parent));
420 current_parent = gprof_call_graph_block_entry_get_next (current_parent_iter,
421 &current_parent_iter);
423 fprintf (stream, "\n---\n\n");
424 current_block = g_list_next (current_block);