~ubuntu-branches/ubuntu/trusty/sysprof/trusty

« back to all changes in this revision

Viewing changes to profile.c

  • Committer: Bazaar Package Importer
  • Author(s): Ritesh Raj Sarraf
  • Date: 2011-06-13 23:05:39 UTC
  • mfrom: (8.1.2 experimental)
  • Revision ID: james.westby@ubuntu.com-20110613230539-426qhsc3k996edou
Tags: 1.1.6-2
Upload to unstable 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Sysprof -- Sampling, systemwide CPU profiler
2
2
 * Copyright 2004, Red Hat, Inc.
3
 
 * Copyright 2004, 2005, Soeren Sandmann
 
3
 * Copyright 2004, 2005, 2006, Soeren Sandmann
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
6
6
 * it under the terms of the GNU General Public License as published by
22
22
#include <string.h>
23
23
 
24
24
#include "binfile.h"
25
 
#include "process.h"
26
25
#include "stackstash.h"
27
26
#include "profile.h"
28
27
#include "sfile.h"
29
28
 
30
 
typedef struct Node Node;
31
 
 
32
 
static void
33
 
update()
34
 
{
35
 
#if 0
36
 
    while (g_main_pending())
37
 
        g_main_iteration (FALSE);
38
 
#endif
39
 
}
40
 
 
41
 
static guint
42
 
direct_hash_no_null (gconstpointer v)
43
 
{
44
 
    g_assert (v != NULL);
45
 
    return GPOINTER_TO_UINT (v);
46
 
}
47
 
 
48
 
struct Node
49
 
{
50
 
    ProfileObject *object;
51
 
    
52
 
    Node *siblings;             /* siblings in the call tree */
53
 
    Node *children;             /* children in the call tree */
54
 
    Node *parent;               /* parent in call tree */
55
 
    Node *next;                 /* nodes that correspond to same object are linked though
56
 
                                 * this pointer
57
 
                                 */
58
 
    
59
 
    guint total;
60
 
    guint self;
61
 
    
62
 
    gboolean toplevel;
63
 
};
64
 
 
65
29
struct Profile
66
30
{
67
 
    gint                size;
68
 
    Node *              call_tree;
69
 
    
70
 
    /* This table is really a cache. We can build it from the call_tree */
71
 
    GHashTable *        nodes_by_object;
 
31
    StackStash *stash;
72
32
};
73
33
 
74
34
static SFormat *
75
35
create_format (void)
76
36
{
77
 
    SType object_type = 0;
78
 
    SType node_type = 0;
 
37
    SFormat *format;
 
38
    SForward *object_forward;
 
39
    SForward *node_forward;
 
40
 
 
41
    format = sformat_new();
 
42
 
 
43
    object_forward = sformat_declare_forward (format);
 
44
    node_forward = sformat_declare_forward (format);
79
45
    
80
 
    return sformat_new (
81
 
        sformat_new_record (
82
 
            "profile", NULL,
83
 
            sformat_new_integer ("size"),
84
 
            sformat_new_pointer ("call_tree", &node_type),
85
 
            sformat_new_list (
86
 
                "objects", NULL,
87
 
                sformat_new_record (
88
 
                    "object", &object_type,
89
 
                    sformat_new_string ("name"),
90
 
                    sformat_new_integer ("total"),
91
 
                    sformat_new_integer ("self"),
 
46
    sformat_set_type (
 
47
        format,
 
48
        sformat_make_record (
 
49
            format, "profile", NULL,
 
50
            sformat_make_integer (format, "size"),
 
51
            sformat_make_pointer (format, "call_tree", node_forward),
 
52
            sformat_make_list (
 
53
                format, "objects", NULL,
 
54
                sformat_make_record (
 
55
                    format, "object", object_forward,
 
56
                    sformat_make_string (format, "name"),
 
57
                    sformat_make_integer (format, "total"),
 
58
                    sformat_make_integer (format, "self"),
92
59
                    NULL)),
93
 
            sformat_new_list (
94
 
                "nodes", NULL,
95
 
                sformat_new_record (
96
 
                    "node", &node_type,
97
 
                    sformat_new_pointer ("object", &object_type),
98
 
                    sformat_new_pointer ("siblings", &node_type),
99
 
                    sformat_new_pointer ("children", &node_type),
100
 
                    sformat_new_pointer ("parent", &node_type),
101
 
                    sformat_new_integer ("total"),
102
 
                    sformat_new_integer ("self"),
103
 
                    sformat_new_integer ("toplevel"),
 
60
            sformat_make_list (
 
61
                format, "nodes", NULL,
 
62
                sformat_make_record (
 
63
                    format, "node", node_forward,
 
64
                    sformat_make_pointer (format, "object", object_forward),
 
65
                    sformat_make_pointer (format, "siblings", node_forward),
 
66
                    sformat_make_pointer (format, "children", node_forward),
 
67
                    sformat_make_pointer (format, "parent", node_forward),
 
68
                    sformat_make_integer (format, "total"),
 
69
                    sformat_make_integer (format, "self"),
 
70
                    sformat_make_integer (format, "toplevel"),
104
71
                    NULL)),
105
72
            NULL));
106
 
}
107
 
 
108
 
static void
109
 
add_object (gpointer key, gpointer value, gpointer data)
110
 
{
111
 
    SFileOutput *output = data;
112
 
    ProfileObject *object = key;
113
 
 
114
 
    sfile_begin_add_record (output, "object");
115
 
 
116
 
    sfile_add_string (output, "name", object->name);
117
 
    sfile_add_integer (output, "total", object->total);
118
 
    sfile_add_integer (output, "self", object->self);
119
 
    
120
 
    sfile_end_add (output, "object", object);
121
 
}
122
 
 
123
 
static void
124
 
serialize_call_tree (Node *node, SFileOutput *output)
 
73
 
 
74
    return format;
 
75
}
 
76
 
 
77
static void
 
78
serialize_call_tree (StackNode *node,
 
79
                     SFileOutput *output)
125
80
{
126
81
    if (!node)
127
82
        return;
128
83
    
129
84
    sfile_begin_add_record (output, "node");
130
 
    sfile_add_pointer (output, "object", node->object);
 
85
    sfile_add_pointer (output, "object", U64_TO_POINTER (node->data));
131
86
    sfile_add_pointer (output, "siblings", node->siblings);
132
87
    sfile_add_pointer (output, "children", node->children);
133
88
    sfile_add_pointer (output, "parent", node->parent);
134
89
    sfile_add_integer (output, "total", node->total);
135
 
    sfile_add_integer (output, "self", node->self);
 
90
    sfile_add_integer (output, "self", node->size);
136
91
    sfile_add_integer (output, "toplevel", node->toplevel);
137
92
    sfile_end_add (output, "node", node);
138
 
 
 
93
    
139
94
    serialize_call_tree (node->siblings, output);
140
95
    serialize_call_tree (node->children, output);
141
96
}
147
102
{
148
103
    gboolean result;
149
104
    
 
105
    GList *profile_objects;
 
106
    GList *list;
 
107
    
150
108
    SFormat *format = create_format ();
151
109
    SFileOutput *output = sfile_output_new (format);
152
 
 
 
110
    
153
111
    sfile_begin_add_record (output, "profile");
154
 
 
155
 
    sfile_add_integer (output, "size", profile->size);
156
 
    sfile_add_pointer (output, "call_tree", profile->call_tree);
157
 
    
 
112
    
 
113
    sfile_add_integer (output, "size", profile_get_size (profile));
 
114
    sfile_add_pointer (output, "call_tree",
 
115
                       stack_stash_get_root (profile->stash));
 
116
    
 
117
    profile_objects = profile_get_objects (profile);
158
118
    sfile_begin_add_list (output, "objects");
159
 
    g_hash_table_foreach (profile->nodes_by_object, add_object, output);
 
119
    for (list = profile_objects; list != NULL; list = list->next)
 
120
    {
 
121
        ProfileObject *object = list->data;
 
122
        
 
123
        sfile_begin_add_record (output, "object");
 
124
        
 
125
        sfile_add_string (output, "name", object->name);
 
126
        sfile_add_integer (output, "total", object->total);
 
127
        sfile_add_integer (output, "self", object->self);
 
128
        
 
129
        sfile_end_add (output, "object", object->name);
 
130
    }
 
131
    g_list_foreach (profile_objects, (GFunc)g_free, NULL);
 
132
    g_list_free (profile_objects);
 
133
    
160
134
    sfile_end_add (output, "objects", NULL);
161
 
 
 
135
    
162
136
    sfile_begin_add_list (output, "nodes");
163
 
    serialize_call_tree (profile->call_tree, output);
 
137
    serialize_call_tree (stack_stash_get_root (profile->stash), output);
164
138
    sfile_end_add (output, "nodes", NULL);
165
 
 
 
139
    
166
140
    sfile_end_add (output, "profile", NULL);
167
 
 
 
141
    
168
142
    result = sfile_output_save (output, file_name, err);
169
 
 
170
 
    sformat_free (format);
 
143
    
171
144
    sfile_output_free (output);
172
 
 
 
145
    sformat_free (format);
 
146
    
173
147
    return result;
174
148
}
175
149
 
176
 
static void
177
 
make_hash_table (Node *node, GHashTable *table)
178
 
{
179
 
    if (!node)
180
 
        return;
181
 
 
182
 
    g_assert (node->object);
183
 
    
184
 
    node->next = g_hash_table_lookup (table, node->object);
185
 
    g_hash_table_insert (table, node->object, node);
186
 
 
187
 
    g_assert (node->siblings != (void *)0x11);
188
 
    
189
 
    make_hash_table (node->siblings, table);
190
 
    make_hash_table (node->children, table);
191
 
}
192
 
 
193
150
Profile *
194
151
profile_load (const char *filename, GError **err)
195
152
{
197
154
    SFileInput *input;
198
155
    Profile *profile;
199
156
    int n, i;
 
157
    StackNode *root;
200
158
    
201
159
    format = create_format ();
202
160
    input = sfile_load (filename, format, err);
203
 
 
 
161
    
204
162
    if (!input)
205
163
        return NULL;
206
164
    
207
165
    profile = g_new (Profile, 1);
208
 
 
209
 
    profile->nodes_by_object =
210
 
        g_hash_table_new (direct_hash_no_null, g_direct_equal);
211
166
    
212
167
    sfile_begin_get_record (input, "profile");
213
 
 
214
 
    sfile_get_integer (input, "size", &profile->size);
215
 
    sfile_get_pointer (input, "call_tree", (void **)&profile->call_tree);
216
 
 
 
168
    
 
169
    sfile_get_integer (input, "size", NULL);
 
170
    sfile_get_pointer (input, "call_tree", (gpointer *)&root);
 
171
    
217
172
    n = sfile_begin_get_list (input, "objects");
218
173
    for (i = 0; i < n; ++i)
219
174
    {
220
 
        ProfileObject *obj = g_new (ProfileObject, 1);
 
175
        char *string;
221
176
        
222
177
        sfile_begin_get_record (input, "object");
223
 
 
224
 
        sfile_get_string (input, "name", &obj->name);
225
 
        sfile_get_integer (input, "total", (gint32 *)&obj->total);
226
 
        sfile_get_integer (input, "self", (gint32 *)&obj->self);
227
 
        
228
 
        sfile_end_get (input, "object", obj);
 
178
        
 
179
        sfile_get_string (input, "name", &string);
 
180
        sfile_get_integer (input, "total", NULL);
 
181
        sfile_get_integer (input, "self", NULL);
 
182
        
 
183
        sfile_end_get (input, "object", string);
229
184
    }
230
185
    sfile_end_get (input, "objects", NULL);
231
186
 
232
 
    profile->call_tree = NULL;
 
187
    profile->stash = stack_stash_new ((GDestroyNotify)g_free);
 
188
    
233
189
    n = sfile_begin_get_list (input, "nodes");
234
190
    for (i = 0; i < n; ++i)
235
191
    {
236
 
        Node *node = g_new (Node, 1);
237
 
 
 
192
        StackNode *node = stack_node_new (profile->stash);
 
193
        gint32 size;
 
194
        gint32 total;
 
195
        
238
196
        sfile_begin_get_record (input, "node");
239
 
 
240
 
        sfile_get_pointer (input, "object", (gpointer *)&node->object);
 
197
        
 
198
        sfile_get_pointer (input, "object", (gpointer *)&node->data);
241
199
        sfile_get_pointer (input, "siblings", (gpointer *)&node->siblings);
242
200
        sfile_get_pointer (input, "children", (gpointer *)&node->children);
243
201
        sfile_get_pointer (input, "parent", (gpointer *)&node->parent);
244
 
        sfile_get_integer (input, "total", (gint32 *)&node->total);
245
 
        sfile_get_integer (input, "self", (gint32 *)&node->self);
246
 
        sfile_get_integer (input, "toplevel", &node->toplevel);
 
202
        sfile_get_integer (input, "total", &total);
 
203
        sfile_get_integer (input, "self", (gint32 *)&size);
 
204
        sfile_get_integer (input, "toplevel", NULL);
 
205
 
 
206
        node->total = total;
 
207
        node->size = size;
247
208
        
248
209
        sfile_end_get (input, "node", node);
249
 
 
 
210
        
250
211
        g_assert (node->siblings != (void *)0x11);
251
212
    }
252
213
    sfile_end_get (input, "nodes", NULL);
253
214
    sfile_end_get (input, "profile", NULL);
254
215
    
255
 
    sformat_free (format);
256
216
    sfile_input_free (input);
 
217
    sformat_free (format);
 
218
 
 
219
    stack_stash_set_root (profile->stash, root);
257
220
    
258
 
    make_hash_table (profile->call_tree, profile->nodes_by_object);
259
 
 
260
221
    return profile;
261
222
}
262
223
 
263
 
static ProfileObject *
264
 
profile_object_new (void)
265
 
{
266
 
    ProfileObject *obj = g_new (ProfileObject, 1);
267
 
    obj->total = 0;
268
 
    obj->self = 0;
269
 
    
270
 
    return obj;
271
 
}
272
 
 
273
 
static void
274
 
profile_object_free (ProfileObject *obj)
275
 
{
276
 
    g_free (obj->name);
277
 
    g_free (obj);
278
 
}
279
 
 
280
 
static char *
281
 
generate_key (Process *process, gulong address)
282
 
{
283
 
    if (address)
284
 
    {
285
 
        const Symbol *symbol = process_lookup_symbol (process, address);
286
 
        
287
 
        return g_strdup_printf ("%p%s", (void *)symbol->address, symbol->name);
288
 
    }
289
 
    else
290
 
    {
291
 
        return g_strdup_printf ("p:%p", process_get_cmdline (process));
292
 
    }
293
 
}
294
 
 
295
 
static char *
296
 
generate_presentation_name (Process *process, gulong address)
297
 
{
298
 
    /* FIXME - not10
299
 
     * using 0 to indicate "process" is broken
300
 
     */
301
 
    if (address)
302
 
    {
303
 
        const Symbol *symbol = process_lookup_symbol (process, address);
304
 
        
305
 
        return g_strdup_printf ("%s", symbol->name);
306
 
    }
307
 
    else
308
 
    {
309
 
        return g_strdup_printf ("%s", process_get_cmdline (process));
310
 
    }
311
 
}
312
 
 
313
 
static void
314
 
ensure_profile_object (GHashTable *profile_objects, Process *process, gulong address)
315
 
{
316
 
    char *key = generate_key (process, address);
317
 
    
318
 
    if (!g_hash_table_lookup (profile_objects, key))
319
 
    {
320
 
        ProfileObject *object;
321
 
        
322
 
        object = profile_object_new ();
323
 
        object->name = generate_presentation_name (process, address);
324
 
        
325
 
        g_hash_table_insert (profile_objects, key, object);
326
 
    }
327
 
    else
328
 
    {
329
 
        g_free (key);
330
 
    }
331
 
}
332
 
 
333
 
static ProfileObject *
334
 
lookup_profile_object (GHashTable *profile_objects, Process *process, gulong address)
335
 
{
336
 
    ProfileObject *object;
337
 
    char *key = generate_key (process, address);
338
 
    object = g_hash_table_lookup (profile_objects, key);
339
 
    g_free (key);
340
 
    g_assert (object);
341
 
    return object;
342
 
}
343
 
 
344
 
typedef struct Info Info;
345
 
struct Info
346
 
{
347
 
    Profile *profile;
348
 
    GHashTable *profile_objects;
349
 
};
350
 
 
351
 
static void
352
 
generate_object_table (Process *process, GSList *trace, gint size, gpointer data)
353
 
{
354
 
    Info *info = data;
355
 
    GSList *list;
356
 
    
357
 
    ensure_profile_object (info->profile_objects, process, 0);
358
 
    
359
 
    for (list = trace; list != NULL; list = list->next)
360
 
    {
361
 
        update ();
362
 
        ensure_profile_object (info->profile_objects, process, (gulong)list->data);
363
 
    }
364
 
    
365
 
    info->profile->size += size;
366
 
}
367
 
 
368
 
static Node *
369
 
node_new ()
370
 
{
371
 
    Node *node = g_new (Node, 1);
372
 
    node->siblings = NULL;
373
 
    node->children = NULL;
374
 
    node->parent = NULL;
375
 
    node->next = NULL;
376
 
    node->object = NULL;
377
 
    node->self = 0;
378
 
    node->total = 0;
379
 
    
380
 
    return node;
381
 
}
382
 
 
383
 
static Node *
384
 
node_add_trace (Profile *profile, GHashTable *profile_objects, Node *node, Process *process,
385
 
                GSList *trace, gint size,
386
 
                GHashTable *seen_objects)
387
 
{
388
 
    ProfileObject *object;
389
 
    Node *match = NULL;
390
 
    
391
 
    if (!trace)
392
 
        return node;
393
 
    
394
 
    object = lookup_profile_object (profile_objects, process, (gulong)trace->data);
395
 
    for (match = node; match != NULL; match = match->siblings)
396
 
    {
397
 
        if (match->object == object)
398
 
            break;
399
 
    }
400
 
    
401
 
    if (!match)
402
 
    {
403
 
        match = node_new ();
404
 
        match->object = object;
405
 
        match->siblings = node;
406
 
        node = match;
407
 
        
408
 
        if (g_hash_table_lookup (seen_objects, object))
409
 
            match->toplevel = FALSE;
410
 
        else
411
 
            match->toplevel = TRUE;
412
 
        
413
 
        match->next = g_hash_table_lookup (profile->nodes_by_object, object);
414
 
        g_hash_table_insert (profile->nodes_by_object, object, match);
415
 
    }
416
 
    
417
 
    g_hash_table_insert (seen_objects, object, GINT_TO_POINTER (1));
418
 
    
419
 
#if 0
420
 
    g_print ("%s adds %d\n", match->object->name, size);
421
 
#endif
422
 
    match->total += size;
423
 
    if (!trace->next)
424
 
        match->self += size;
425
 
    
426
 
    match->children = node_add_trace (profile, profile_objects, match->children, process, trace->next, size,
427
 
                                      seen_objects);
428
 
    
429
 
    return node;
430
 
}
431
 
 
432
 
#if 0
433
 
static void
434
 
dump_trace (GSList *trace)
435
 
{
436
 
    g_print ("TRACE: ");
437
 
    while (trace)
438
 
    {
439
 
        g_print ("%x ", trace->data);
440
 
        trace = trace->next;
441
 
    }
442
 
    g_print ("\n\n");
443
 
}
444
 
#endif
445
 
 
446
 
static void
447
 
generate_call_tree (Process *process, GSList *trace, gint size, gpointer data)
448
 
{
449
 
    Info *info = data;
450
 
    Node *match = NULL;
451
 
    ProfileObject *proc = lookup_profile_object (info->profile_objects, process, 0);
452
 
    GHashTable *seen_objects;
453
 
    
454
 
    for (match = info->profile->call_tree; match; match = match->siblings)
455
 
    {
456
 
        if (match->object == proc)
457
 
            break;
458
 
    }
459
 
    
460
 
    if (!match)
461
 
    {
462
 
        match = node_new ();
463
 
        match->object = proc;
464
 
        match->siblings = info->profile->call_tree;
465
 
        info->profile->call_tree = match;
466
 
        match->toplevel = TRUE;
467
 
    }
468
 
    
469
 
    g_hash_table_insert (info->profile->nodes_by_object, proc, match);
470
 
    
471
 
    match->total += size;
472
 
    if (!trace)
473
 
        match->self += size;
474
 
    
475
 
    seen_objects = g_hash_table_new (direct_hash_no_null, g_direct_equal);
476
 
    
477
 
    g_hash_table_insert (seen_objects, proc, GINT_TO_POINTER (1));
478
 
    
479
 
    update ();
480
 
    match->children = node_add_trace (info->profile, info->profile_objects, match->children, process,
481
 
                                      trace, size, seen_objects);
482
 
    
483
 
    g_hash_table_destroy (seen_objects);
484
 
}
485
 
 
486
 
static void
487
 
link_parents (Node *node, Node *parent)
488
 
{
489
 
    if (!node)
490
 
        return;
491
 
    
492
 
    node->parent = parent;
493
 
    
494
 
    link_parents (node->siblings, parent);
495
 
    link_parents (node->children, node);
496
 
}
497
 
 
498
 
static void
499
 
compute_object_total (gpointer key, gpointer value, gpointer data)
500
 
{
501
 
    Node *node;
502
 
    ProfileObject *object = key;
503
 
    
504
 
    for (node = value; node != NULL; node = node->next)
505
 
    {
506
 
        object->self += node->self;
507
 
        if (node->toplevel)
508
 
            object->total += node->total;
509
 
    }
510
 
}
511
 
 
512
224
Profile *
513
225
profile_new (StackStash *stash)
514
226
{
515
 
    Info info;
516
 
 
517
 
    info.profile = g_new (Profile, 1);
518
 
    info.profile->call_tree = NULL;
519
 
    info.profile->nodes_by_object =
520
 
        g_hash_table_new (direct_hash_no_null, g_direct_equal);
521
 
    info.profile->size = 0;
522
 
 
523
 
    /* profile objects */
524
 
    info.profile_objects = g_hash_table_new_full (g_str_hash, g_str_equal,
525
 
                                                  g_free, NULL);
526
 
 
527
 
    stack_stash_foreach (stash, generate_object_table, &info);
528
 
    stack_stash_foreach (stash, generate_call_tree, &info);
529
 
    link_parents (info.profile->call_tree, NULL);
530
 
    
531
 
    g_hash_table_foreach (info.profile->nodes_by_object, compute_object_total, NULL);
532
 
    
533
 
    g_hash_table_destroy (info.profile_objects);
534
 
 
535
 
    return info.profile;
 
227
    Profile *profile = g_new (Profile, 1);
 
228
    
 
229
    profile->stash = stack_stash_ref (stash);
 
230
    
 
231
    return profile;
536
232
}
537
233
 
538
234
static void
539
 
add_trace_to_tree (ProfileDescendant **tree, GList *trace, guint size)
 
235
add_trace_to_tree (StackLink *trace, gint size, gpointer data)
540
236
{
541
 
    GList *list;
542
 
    GPtrArray *nodes_to_unmark = g_ptr_array_new ();
543
 
    GPtrArray *nodes_to_unmark_recursive = g_ptr_array_new ();
 
237
    StackLink *link;
544
238
    ProfileDescendant *parent = NULL;
545
 
    int i, len;
546
 
    
547
 
    GPtrArray *seen_objects = g_ptr_array_new ();
548
 
    
549
 
    for (list = trace; list != NULL; list = list->next)
 
239
    ProfileDescendant **tree = data;
 
240
 
 
241
    link = trace;
 
242
    while (link->next)
 
243
        link = link->next;
 
244
 
 
245
    for (; link != NULL; link = link->prev)
550
246
    {
551
 
        Node *node = list->data;
 
247
        gpointer address = U64_TO_POINTER (link->data);
 
248
        ProfileDescendant *prev = NULL;
552
249
        ProfileDescendant *match = NULL;
553
 
        
554
 
        update();
555
 
        
556
 
        for (match = *tree; match != NULL; match = match->siblings)
 
250
 
 
251
        for (match = *tree; match != NULL; prev = match, match = match->siblings)
557
252
        {
558
 
            if (match->object == node->object)
 
253
            if (match->name == address)
 
254
            {
 
255
                if (prev)
 
256
                {
 
257
                    /* Move to front */
 
258
                    prev->siblings = match->siblings;
 
259
                    match->siblings = *tree;
 
260
                    *tree = match;
 
261
                }
559
262
                break;
 
263
            }
560
264
        }
561
265
        
562
266
        if (!match)
563
267
        {
564
 
            ProfileDescendant *seen_tree_node;
565
 
            
566
268
            /* Have we seen this object further up the tree? */
567
 
            seen_tree_node = NULL;
568
 
            for (i = 0; i < seen_objects->len; ++i)
569
 
            {
570
 
                ProfileDescendant *n = seen_objects->pdata[i];
571
 
                if (n->object == node->object)
572
 
                    seen_tree_node = n;
573
 
            }
574
 
                    
575
 
            if (seen_tree_node)
576
 
            {
577
 
                ProfileDescendant *node;
578
 
                
579
 
                g_assert (parent);
580
 
                
581
 
                for (node = parent; node != seen_tree_node->parent; node = node->parent)
582
 
                {
583
 
                    node->non_recursion -= size;
584
 
                    --node->marked_non_recursive;
585
 
                }
586
 
                
587
 
                match = seen_tree_node;
588
 
                
589
 
                g_ptr_array_remove_range (seen_objects, 0, seen_objects->len);
590
 
                for (node = match; node != NULL; node = node->parent)
591
 
                    g_ptr_array_add (seen_objects, node);
 
269
            for (match = parent; match != NULL; match = match->parent)
 
270
            {
 
271
                if (match->name == address)
 
272
                    break;
592
273
            }
593
274
        }
594
275
        
596
277
        {
597
278
            match = g_new (ProfileDescendant, 1);
598
279
            
599
 
            match->object = node->object;
600
 
            match->non_recursion = 0;
601
 
            match->total = 0;
 
280
            match->name = address;
 
281
            match->cumulative = 0;
602
282
            match->self = 0;
603
283
            match->children = NULL;
604
 
            match->marked_non_recursive = 0;
605
 
            match->marked_total = FALSE;
606
284
            match->parent = parent;
607
 
            
608
285
            match->siblings = *tree;
609
286
            *tree = match;
610
287
        }
611
288
        
612
 
        if (!match->marked_non_recursive)
613
 
        {
614
 
            g_ptr_array_add (nodes_to_unmark, match);
615
 
            match->non_recursion += size;
616
 
            ++match->marked_non_recursive;
617
 
        }
618
 
        
619
 
        if (!match->marked_total)
620
 
        {
621
 
            g_ptr_array_add (nodes_to_unmark_recursive, match);
622
 
            
623
 
            match->total += size;
624
 
            match->marked_total = TRUE;
625
 
        }
626
 
        
627
 
        if (!list->next)
628
 
            match->self += size;
629
 
 
630
 
        g_ptr_array_add (seen_objects, match);
631
 
        
632
289
        tree = &(match->children);
633
290
        parent = match;
634
291
    }
635
292
 
636
 
    g_ptr_array_free (seen_objects, TRUE);
637
 
 
638
 
    len = nodes_to_unmark->len;
639
 
    for (i = 0; i < len; ++i)
640
 
    {
641
 
        ProfileDescendant *tree_node = nodes_to_unmark->pdata[i];
642
 
        
643
 
        tree_node->marked_non_recursive = 0;
644
 
    }
645
 
 
646
 
    len = nodes_to_unmark_recursive->len;
647
 
    for (i = 0; i < len; ++i)
648
 
    {
649
 
        ProfileDescendant *tree_node = nodes_to_unmark_recursive->pdata[i];
650
 
        
651
 
        tree_node->marked_total = FALSE;
652
 
    }
653
 
 
654
 
    g_ptr_array_free (nodes_to_unmark, TRUE);
655
 
    g_ptr_array_free (nodes_to_unmark_recursive, TRUE);
656
 
}
657
 
 
658
 
static void
659
 
node_list_leaves (Node *node, GList **leaves)
660
 
{
661
 
    Node *n;
662
 
    
663
 
    if (node->self > 0)
664
 
        *leaves = g_list_prepend (*leaves, node);
665
 
    
666
 
    for (n = node->children; n != NULL; n = n->siblings)
667
 
        node_list_leaves (n, leaves);
668
 
}
669
 
 
670
 
static void
671
 
add_leaf_to_tree (ProfileDescendant **tree, Node *leaf, Node *top)
672
 
{
673
 
    GList *trace = NULL;
674
 
    Node *node;
675
 
    
676
 
    for (node = leaf; node != top->parent; node = node->parent)
677
 
        trace = g_list_prepend (trace, node);
678
 
    
679
 
    add_trace_to_tree (tree, trace, leaf->self);
680
 
    
681
 
    g_list_free (trace);
 
293
    parent->self += size;
 
294
    while (parent)
 
295
    {
 
296
        parent->cumulative += size;
 
297
        parent = parent->parent;
 
298
    }
682
299
}
683
300
 
684
301
ProfileDescendant *
685
 
profile_create_descendants (Profile *profile, ProfileObject *object)
 
302
profile_create_descendants (Profile *profile,
 
303
                            char *object_name)
686
304
{
687
305
    ProfileDescendant *tree = NULL;
688
 
    Node *node;
689
306
    
690
 
    node = g_hash_table_lookup (profile->nodes_by_object, object);
 
307
    StackNode *node = stack_stash_find_node (profile->stash, object_name);
691
308
    
692
309
    while (node)
693
310
    {
694
 
        update();
695
311
        if (node->toplevel)
696
 
        {
697
 
            GList *leaves = NULL;
698
 
            GList *list;
699
 
            
700
 
            node_list_leaves (node, &leaves);
701
 
            
702
 
            for (list = leaves; list != NULL; list = list->next)
703
 
                add_leaf_to_tree (&tree, list->data, node);
704
 
            
705
 
            g_list_free (leaves);
706
 
        }
 
312
            stack_node_foreach_trace (node, add_trace_to_tree, &tree);
 
313
        
707
314
        node = node->next;
708
315
    }
709
316
    
714
321
profile_caller_new (void)
715
322
{
716
323
    ProfileCaller *caller = g_new (ProfileCaller, 1);
 
324
 
717
325
    caller->next = NULL;
718
326
    caller->self = 0;
719
327
    caller->total = 0;
 
328
 
720
329
    return caller;
721
330
}
722
331
 
723
332
ProfileCaller *
724
 
profile_list_callers (Profile       *profile,
725
 
                      ProfileObject *callee)
 
333
profile_list_callers (Profile *profile,
 
334
                      char    *callee_name)
726
335
{
727
 
    Node *callee_node;
728
 
    Node *node;
729
 
    GHashTable *callers_by_object;
730
 
    GHashTable *seen_callers;
 
336
    StackNode *node;
 
337
    StackNode *callees;
 
338
    GHashTable *callers_by_name;
 
339
    GHashTable *processed_callers;
731
340
    ProfileCaller *result = NULL;
732
 
    
733
 
    callers_by_object =
734
 
        g_hash_table_new (g_direct_hash, g_direct_equal);
735
 
    seen_callers = g_hash_table_new (g_direct_hash, g_direct_equal);
736
 
    
737
 
    callee_node = g_hash_table_lookup (profile->nodes_by_object, callee);
738
 
    
739
 
    for (node = callee_node; node; node = node->next)
 
341
 
 
342
    callers_by_name = g_hash_table_new (g_direct_hash, g_direct_equal);
 
343
    processed_callers = g_hash_table_new (g_direct_hash, g_direct_equal);
 
344
    
 
345
    callees = stack_stash_find_node (profile->stash, callee_name);
 
346
 
 
347
    for (node = callees; node != NULL; node = node->next)
740
348
    {
741
 
        ProfileObject *object;
742
 
        if (node->parent)
743
 
            object = node->parent->object;
744
 
        else
745
 
            object = NULL;
746
 
        
747
 
        if (!g_hash_table_lookup (callers_by_object, object))
 
349
        ProfileCaller *caller;
 
350
        
 
351
        if (!node->parent)
 
352
            continue;
 
353
        
 
354
        caller = g_hash_table_lookup (
 
355
            callers_by_name, U64_TO_POINTER (node->parent->data));
 
356
        
 
357
        if (!caller)
748
358
        {
749
 
            ProfileCaller *caller = profile_caller_new ();
750
 
            caller->object = object;
751
 
            g_hash_table_insert (callers_by_object, object, caller);
 
359
            caller = profile_caller_new ();
 
360
            caller->name = U64_TO_POINTER (node->parent->data);
 
361
            caller->total = 0;
 
362
            caller->self = 0;
752
363
            
753
364
            caller->next = result;
754
365
            result = caller;
 
366
            
 
367
            g_hash_table_insert (
 
368
                callers_by_name, U64_TO_POINTER (node->parent->data), caller);
755
369
        }
756
370
    }
757
371
    
758
 
    for (node = callee_node; node != NULL; node = node->next)
759
 
    {
760
 
        Node *top_caller;
761
 
        Node *top_callee;
762
 
        Node *n;
 
372
    for (node = callees; node != NULL; node = node->next)
 
373
    {   
 
374
        StackNode *top_caller = node->parent;
 
375
        StackNode *top_callee = node;
 
376
        StackNode *n;
763
377
        ProfileCaller *caller;
764
 
        ProfileObject *object;
765
 
        
766
 
        if (node->parent)
767
 
            object = node->parent->object;
768
 
        else
769
 
            object = NULL;
770
 
        
771
 
        caller = g_hash_table_lookup (callers_by_object, object);
772
 
        
773
 
        /* find topmost node/parent pair identical to this node/parent */
774
 
        top_caller = node->parent;
775
 
        top_callee = node;
 
378
 
 
379
        if (!node->parent)
 
380
            continue;
 
381
        
776
382
        for (n = node; n && n->parent; n = n->parent)
777
383
        {
778
 
            if (n->object == node->object                  &&
779
 
                n->parent->object == node->parent->object)
 
384
            if (n->data == node->data           &&
 
385
                n->parent->data == node->parent->data)
780
386
            {
781
387
                top_caller = n->parent;
782
388
                top_callee = n;
783
389
            }
784
390
        }
 
391
 
 
392
        caller = g_hash_table_lookup (
 
393
            callers_by_name, U64_TO_POINTER (node->parent->data));
785
394
        
786
 
        if (!g_hash_table_lookup (seen_callers, top_caller))
 
395
        if (!g_hash_table_lookup (processed_callers, top_caller))
787
396
        {
788
397
            caller->total += top_callee->total;
789
398
            
790
 
            g_hash_table_insert (seen_callers, top_caller, (void *)0x1);
 
399
            g_hash_table_insert (processed_callers, top_caller, top_caller);
791
400
        }
792
401
        
793
 
        if (node->self > 0)
794
 
            caller->self += node->self;
795
 
    }
796
 
    
797
 
    g_hash_table_destroy (seen_callers);
798
 
    g_hash_table_destroy (callers_by_object);
799
 
    
800
 
    return result;
801
 
    
802
 
}
803
 
 
804
 
static void
805
 
node_free (Node *node)
806
 
{
807
 
    if (!node)
808
 
        return;
809
 
    
810
 
    node_free (node->siblings);
811
 
    node_free (node->children);
812
 
    g_free (node);
813
 
}
814
 
 
815
 
static void
816
 
free_object (gpointer key, gpointer value, gpointer data)
817
 
{
818
 
    profile_object_free (key);
819
 
}
 
402
        caller->self += node->size;
 
403
    }
 
404
 
 
405
    g_hash_table_destroy (processed_callers);
 
406
    g_hash_table_destroy (callers_by_name);
 
407
 
 
408
    return result;
 
409
}
 
410
 
 
411
#if 0
 
412
/* This code generates a list of all ancestors, rather than
 
413
 * all callers. It turned out to not work well in practice,
 
414
 * but on the other hand the single list of callers is not
 
415
 * all that great either, so we'll keep it around commented
 
416
 * out for now
 
417
 */
 
418
 
 
419
static void
 
420
add_to_list (gpointer key,
 
421
             gpointer value,
 
422
             gpointer user_data)
 
423
{
 
424
    GList **list = user_data;
 
425
 
 
426
    *list = g_list_prepend (*list, value);
 
427
}
 
428
 
 
429
static GList *
 
430
listify_hash_table (GHashTable *hash_table)
 
431
{
 
432
    GList *result = NULL;
 
433
    
 
434
    g_hash_table_foreach (hash_table, add_to_list, &result);
 
435
 
 
436
    return result;
 
437
}
 
438
 
 
439
ProfileCaller *
 
440
profile_list_ancestors (Profile       *profile,
 
441
                        char          *callee_name)
 
442
{
 
443
    StackNode *callees;
 
444
    StackNode *node;
 
445
    GHashTable *callers_by_name;
 
446
    ProfileCaller *result = NULL;
 
447
 
 
448
    callers_by_name = g_hash_table_new (g_direct_hash, g_direct_equal);
 
449
    
 
450
    callees = stack_stash_find_node (profile->stash, callee_name);
 
451
 
 
452
    for (node = callees; node != NULL; node = node->next)
 
453
    {
 
454
        StackNode *n;
 
455
        gboolean seen_recursive_call;
 
456
        GHashTable *total_ancestors;
 
457
        GHashTable *all_ancestors;
 
458
        GList *all, *list;
 
459
 
 
460
        /* Build a list of those ancestors that should get assigned
 
461
         * totals. If this callee does not have any recursive calls
 
462
         * higher up, that means all of it's ancestors. If it does
 
463
         * have a recursive call, only the one between this node
 
464
         * and the recursive call should get assigned total
 
465
         */
 
466
        seen_recursive_call = FALSE;
 
467
        all_ancestors = g_hash_table_new (g_direct_hash, g_direct_equal);
 
468
        total_ancestors = g_hash_table_new (g_direct_hash, g_direct_equal);
 
469
        for (n = node->parent; n; n = n->parent)
 
470
        {
 
471
            if (!seen_recursive_call)
 
472
            {
 
473
                g_hash_table_insert (total_ancestors, n->address, n);
 
474
            }
 
475
            else
 
476
            {
 
477
                g_hash_table_remove (total_ancestors, n->address);
 
478
            }
 
479
 
 
480
            g_hash_table_insert (all_ancestors, n->address, n);
 
481
 
 
482
            if (n->address == node->address)
 
483
                seen_recursive_call = TRUE;
 
484
        }
 
485
 
 
486
        all = listify_hash_table (all_ancestors);
 
487
 
 
488
        for (list = all; list; list = list->next)
 
489
        {
 
490
            ProfileCaller *caller;
 
491
            StackNode *ancestor = list->data;
 
492
 
 
493
            caller = g_hash_table_lookup (callers_by_name, ancestor->address);
 
494
 
 
495
            if (!caller)
 
496
            {
 
497
                caller = profile_caller_new ();
 
498
                g_hash_table_insert (
 
499
                    callers_by_name, ancestor->address, caller);
 
500
                caller->name = ancestor->address;
 
501
 
 
502
                caller->next = result;
 
503
                result = caller;
 
504
            }
 
505
 
 
506
            caller->self += node->size;
 
507
 
 
508
            if (g_hash_table_lookup (total_ancestors, ancestor->address))
 
509
                caller->total += node->total;
 
510
        }
 
511
 
 
512
        g_list_free (all);
 
513
        g_hash_table_destroy (all_ancestors);
 
514
        g_hash_table_destroy (total_ancestors);
 
515
    }
 
516
 
 
517
    return result;
 
518
}
 
519
#endif
820
520
 
821
521
void
822
522
profile_free (Profile *profile)
823
523
{
824
 
    g_hash_table_foreach (profile->nodes_by_object, free_object, NULL);
825
 
    
826
 
    node_free (profile->call_tree);
827
 
    
828
 
    g_hash_table_destroy (profile->nodes_by_object);
829
 
    
 
524
    stack_stash_unref (profile->stash);
830
525
    g_free (profile);
831
526
}
832
527
 
833
528
void
834
 
profile_descendant_free    (ProfileDescendant *descendant)
 
529
profile_descendant_free (ProfileDescendant *descendant)
835
530
{
836
531
    if (!descendant)
837
532
        return;
852
547
    g_free (caller);
853
548
}
854
549
 
 
550
static int
 
551
compute_total (StackNode *node)
 
552
{
 
553
    StackNode *n;
 
554
    int total = 0;
 
555
 
 
556
    for (n = node; n != NULL; n = n->next)
 
557
    {
 
558
        if (n->toplevel)
 
559
            total += n->total;
 
560
    }
 
561
 
 
562
    return total;
 
563
}
 
564
 
855
565
static void
856
 
build_object_list (gpointer key, gpointer value, gpointer data)
 
566
build_object_list (StackNode *node, gpointer data)
857
567
{
858
 
    ProfileObject *object = key;
859
568
    GList **objects = data;
860
 
    
861
 
    *objects = g_list_prepend (*objects, object);
 
569
    ProfileObject *obj;
 
570
    StackNode *n;
 
571
    
 
572
    obj = g_new (ProfileObject, 1);
 
573
    obj->name = U64_TO_POINTER (node->data);
 
574
 
 
575
    obj->total = compute_total (node);
 
576
    obj->self = 0;
 
577
    
 
578
    for (n = node; n != NULL; n = n->next)
 
579
        obj->self += n->size;
 
580
    
 
581
    *objects = g_list_prepend (*objects, obj);
862
582
}
863
583
 
864
584
GList *
866
586
{
867
587
    GList *objects = NULL;
868
588
    
869
 
    g_hash_table_foreach (profile->nodes_by_object, build_object_list, &objects);
 
589
    stack_stash_foreach_by_address (
 
590
        profile->stash, build_object_list, &objects);
870
591
    
871
592
    return objects;
872
593
}
874
595
gint
875
596
profile_get_size (Profile *profile)
876
597
{
877
 
    return profile->size;
 
598
    StackNode *n;
 
599
    gint size = 0;
 
600
 
 
601
    for (n = stack_stash_get_root (profile->stash); n != NULL; n = n->siblings)
 
602
        size += n->total;
 
603
 
 
604
    return size;
878
605
}