mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2026-02-11 23:51:06 +00:00
TODO
This commit is contained in:
38
TODO
38
TODO
@ -23,7 +23,7 @@ Before 1.2:
|
|||||||
esp0 points to top of kernel stack
|
esp0 points to top of kernel stack
|
||||||
esp points to top of user stack
|
esp points to top of user stack
|
||||||
|
|
||||||
(Reported by Kjartan Marass).
|
(Reported by Kjartan Maraas).
|
||||||
|
|
||||||
- Fix bugs/performance issues:
|
- Fix bugs/performance issues:
|
||||||
- total should probably be cached so that compute_total() doesn't
|
- total should probably be cached so that compute_total() doesn't
|
||||||
@ -58,11 +58,38 @@ Before 1.2:
|
|||||||
- don't leak the presentation strings/objects
|
- don't leak the presentation strings/objects
|
||||||
- loading and saving probably leak right now
|
- loading and saving probably leak right now
|
||||||
|
|
||||||
- think about loading and saving. Goals
|
- rethink loading and saving. Goals
|
||||||
- Can load 1.0 profiles
|
- Can load 1.0 profiles
|
||||||
- Don't export too much of stackstashes to the rest of the
|
- Don't export too much of stackstashes to the rest of the
|
||||||
app
|
app
|
||||||
|
|
||||||
|
Features:
|
||||||
|
|
||||||
|
* Have a compatibility module that can load 1.0 modules
|
||||||
|
- reads in the call tree, then generate a stack stash
|
||||||
|
by repeatedly adding traces.
|
||||||
|
|
||||||
|
* Make stackstash able to save themselves using callbacks.
|
||||||
|
|
||||||
|
* If loading a file fails, then try loading it using the
|
||||||
|
1.0 loader.
|
||||||
|
- optimization: make sure we fail immediately if we
|
||||||
|
see an unknown object.
|
||||||
|
|
||||||
|
* Add versioning support to sfile.[ch]:
|
||||||
|
- sformat_new() should take doctype and version strings:
|
||||||
|
like "sysprof-profile" "version 1.2"
|
||||||
|
- there should be sfile_sniff() functionality that will
|
||||||
|
return the doctype and version of a file. Or None
|
||||||
|
if there aren't any.
|
||||||
|
|
||||||
|
* At this point, make the loader first check if the file has a version
|
||||||
|
if it doesn't, load as 1.0, otherwise as whatever the version claims
|
||||||
|
it is.
|
||||||
|
|
||||||
|
* Make provisions for forward compatibility: maybe it should be possible
|
||||||
|
to load records with more fields than specified.
|
||||||
|
|
||||||
* Figure out how to make sfile.[ch] use less memory.
|
* Figure out how to make sfile.[ch] use less memory.
|
||||||
- In general clean sfile.[ch] up a little:
|
- In general clean sfile.[ch] up a little:
|
||||||
- split out dfa in its own generic class
|
- split out dfa in its own generic class
|
||||||
@ -88,8 +115,11 @@ Before 1.2:
|
|||||||
kernel stack and user space stack, have userspace stitch them
|
kernel stack and user space stack, have userspace stitch them
|
||||||
together. well, they could be stitched together in the kernel.
|
together. well, they could be stitched together in the kernel.
|
||||||
Already done: we now take a stacktrace of the user space process
|
Already done: we now take a stacktrace of the user space process
|
||||||
when the interrupt happens in kernel mode. We don't take any
|
when the interrupt happens in kernel mode. (Unfortunately, this
|
||||||
stacktraces of the kernel though. Things that need to be investigated:
|
causes lockups on many kernels).
|
||||||
|
|
||||||
|
We don't take any stacktraces of the kernel though. Things that need to be
|
||||||
|
investigated:
|
||||||
- does the kernel come with dwarf debug information?
|
- does the kernel come with dwarf debug information?
|
||||||
- does the kernel come with some other debug info
|
- does the kernel come with some other debug info
|
||||||
- is there a place where the vmlinux binary is usually
|
- is there a place where the vmlinux binary is usually
|
||||||
|
|||||||
95
profile.c
95
profile.c
@ -87,10 +87,10 @@ sum_children (StackNode *node)
|
|||||||
* maintain or compute it in the stackstash
|
* maintain or compute it in the stackstash
|
||||||
*/
|
*/
|
||||||
total = node->size;
|
total = node->size;
|
||||||
|
|
||||||
for (child = node->children; child != NULL; child = child->siblings)
|
for (child = node->children; child != NULL; child = child->siblings)
|
||||||
total += sum_children (child);
|
total += sum_children (child);
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,13 +99,13 @@ compute_total (StackNode *node)
|
|||||||
{
|
{
|
||||||
StackNode *n;
|
StackNode *n;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
|
||||||
for (n = node; n != NULL; n = n->next)
|
for (n = node; n != NULL; n = n->next)
|
||||||
{
|
{
|
||||||
if (n->toplevel)
|
if (n->toplevel)
|
||||||
total += sum_children (n);
|
total += sum_children (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ serialize_call_tree (StackNode *node,
|
|||||||
sfile_add_integer (output, "self", node->size);
|
sfile_add_integer (output, "self", node->size);
|
||||||
sfile_add_integer (output, "toplevel", node->toplevel);
|
sfile_add_integer (output, "toplevel", node->toplevel);
|
||||||
sfile_end_add (output, "node", node);
|
sfile_end_add (output, "node", node);
|
||||||
|
|
||||||
serialize_call_tree (node->siblings, output);
|
serialize_call_tree (node->siblings, output);
|
||||||
serialize_call_tree (node->children, output);
|
serialize_call_tree (node->children, output);
|
||||||
}
|
}
|
||||||
@ -136,15 +136,15 @@ profile_save (Profile *profile,
|
|||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
gboolean result;
|
gboolean result;
|
||||||
|
|
||||||
GList *profile_objects;
|
GList *profile_objects;
|
||||||
GList *list;
|
GList *list;
|
||||||
|
|
||||||
SFormat *format = create_format ();
|
SFormat *format = create_format ();
|
||||||
SFileOutput *output = sfile_output_new (format);
|
SFileOutput *output = sfile_output_new (format);
|
||||||
|
|
||||||
sfile_begin_add_record (output, "profile");
|
sfile_begin_add_record (output, "profile");
|
||||||
|
|
||||||
sfile_add_integer (output, "size", profile_get_size (profile));
|
sfile_add_integer (output, "size", profile_get_size (profile));
|
||||||
sfile_add_pointer (output, "call_tree",
|
sfile_add_pointer (output, "call_tree",
|
||||||
stack_stash_get_root (profile->stash));
|
stack_stash_get_root (profile->stash));
|
||||||
@ -167,18 +167,18 @@ profile_save (Profile *profile,
|
|||||||
g_list_free (profile_objects);
|
g_list_free (profile_objects);
|
||||||
|
|
||||||
sfile_end_add (output, "objects", NULL);
|
sfile_end_add (output, "objects", NULL);
|
||||||
|
|
||||||
sfile_begin_add_list (output, "nodes");
|
sfile_begin_add_list (output, "nodes");
|
||||||
serialize_call_tree (stack_stash_get_root (profile->stash), output);
|
serialize_call_tree (stack_stash_get_root (profile->stash), output);
|
||||||
sfile_end_add (output, "nodes", NULL);
|
sfile_end_add (output, "nodes", NULL);
|
||||||
|
|
||||||
sfile_end_add (output, "profile", NULL);
|
sfile_end_add (output, "profile", NULL);
|
||||||
|
|
||||||
result = sfile_output_save (output, file_name, err);
|
result = sfile_output_save (output, file_name, err);
|
||||||
|
|
||||||
sformat_free (format);
|
sformat_free (format);
|
||||||
sfile_output_free (output);
|
sfile_output_free (output);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,12 +188,12 @@ make_hash_table (Node *node, GHashTable *table)
|
|||||||
{
|
{
|
||||||
if (!node)
|
if (!node)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
g_assert (node->object);
|
g_assert (node->object);
|
||||||
|
|
||||||
node->next = g_hash_table_lookup (table, node->object);
|
node->next = g_hash_table_lookup (table, node->object);
|
||||||
g_hash_table_insert (table, node->object, node);
|
g_hash_table_insert (table, node->object, node);
|
||||||
|
|
||||||
g_assert (node->siblings != (void *)0x11);
|
g_assert (node->siblings != (void *)0x11);
|
||||||
|
|
||||||
make_hash_table (node->siblings, table);
|
make_hash_table (node->siblings, table);
|
||||||
@ -212,24 +212,24 @@ profile_load (const char *filename, GError **err)
|
|||||||
|
|
||||||
format = create_format ();
|
format = create_format ();
|
||||||
input = sfile_load (filename, format, err);
|
input = sfile_load (filename, format, err);
|
||||||
|
|
||||||
if (!input)
|
if (!input)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
profile = g_new (Profile, 1);
|
profile = g_new (Profile, 1);
|
||||||
|
|
||||||
sfile_begin_get_record (input, "profile");
|
sfile_begin_get_record (input, "profile");
|
||||||
|
|
||||||
sfile_get_integer (input, "size", NULL);
|
sfile_get_integer (input, "size", NULL);
|
||||||
sfile_get_pointer (input, "call_tree", (gpointer *)&root);
|
sfile_get_pointer (input, "call_tree", (gpointer *)&root);
|
||||||
|
|
||||||
n = sfile_begin_get_list (input, "objects");
|
n = sfile_begin_get_list (input, "objects");
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
char *string;
|
char *string;
|
||||||
|
|
||||||
sfile_begin_get_record (input, "object");
|
sfile_begin_get_record (input, "object");
|
||||||
|
|
||||||
sfile_get_string (input, "name", &string);
|
sfile_get_string (input, "name", &string);
|
||||||
sfile_get_integer (input, "total", NULL);
|
sfile_get_integer (input, "total", NULL);
|
||||||
sfile_get_integer (input, "self", NULL);
|
sfile_get_integer (input, "self", NULL);
|
||||||
@ -237,14 +237,14 @@ profile_load (const char *filename, GError **err)
|
|||||||
sfile_end_get (input, "object", string);
|
sfile_end_get (input, "object", string);
|
||||||
}
|
}
|
||||||
sfile_end_get (input, "objects", NULL);
|
sfile_end_get (input, "objects", NULL);
|
||||||
|
|
||||||
n = sfile_begin_get_list (input, "nodes");
|
n = sfile_begin_get_list (input, "nodes");
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
StackNode *node = g_new (StackNode, 1);
|
StackNode *node = g_new (StackNode, 1);
|
||||||
|
|
||||||
sfile_begin_get_record (input, "node");
|
sfile_begin_get_record (input, "node");
|
||||||
|
|
||||||
sfile_get_pointer (input, "object", (gpointer *)&node->address);
|
sfile_get_pointer (input, "object", (gpointer *)&node->address);
|
||||||
sfile_get_pointer (input, "siblings", (gpointer *)&node->siblings);
|
sfile_get_pointer (input, "siblings", (gpointer *)&node->siblings);
|
||||||
sfile_get_pointer (input, "children", (gpointer *)&node->children);
|
sfile_get_pointer (input, "children", (gpointer *)&node->children);
|
||||||
@ -254,7 +254,7 @@ profile_load (const char *filename, GError **err)
|
|||||||
sfile_get_integer (input, "toplevel", &node->toplevel);
|
sfile_get_integer (input, "toplevel", &node->toplevel);
|
||||||
|
|
||||||
sfile_end_get (input, "node", node);
|
sfile_end_get (input, "node", node);
|
||||||
|
|
||||||
g_assert (node->siblings != (void *)0x11);
|
g_assert (node->siblings != (void *)0x11);
|
||||||
}
|
}
|
||||||
sfile_end_get (input, "nodes", NULL);
|
sfile_end_get (input, "nodes", NULL);
|
||||||
@ -262,7 +262,7 @@ profile_load (const char *filename, GError **err)
|
|||||||
|
|
||||||
sformat_free (format);
|
sformat_free (format);
|
||||||
sfile_input_free (input);
|
sfile_input_free (input);
|
||||||
|
|
||||||
profile->stash = stack_stash_new_from_root (root);
|
profile->stash = stack_stash_new_from_root (root);
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
@ -272,9 +272,9 @@ Profile *
|
|||||||
profile_new (StackStash *stash)
|
profile_new (StackStash *stash)
|
||||||
{
|
{
|
||||||
Profile *profile = g_new (Profile, 1);
|
Profile *profile = g_new (Profile, 1);
|
||||||
|
|
||||||
profile->stash = stash;
|
profile->stash = stash;
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ add_trace_to_tree (ProfileDescendant **tree, GList *trace, guint size)
|
|||||||
if (n->name == node->address)
|
if (n->name == node->address)
|
||||||
seen_tree_node = n;
|
seen_tree_node = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seen_tree_node)
|
if (seen_tree_node)
|
||||||
{
|
{
|
||||||
ProfileDescendant *node;
|
ProfileDescendant *node;
|
||||||
@ -369,15 +369,15 @@ add_trace_to_tree (ProfileDescendant **tree, GList *trace, guint size)
|
|||||||
|
|
||||||
if (!list->next)
|
if (!list->next)
|
||||||
match->self += size;
|
match->self += size;
|
||||||
|
|
||||||
g_ptr_array_add (seen_objects, match);
|
g_ptr_array_add (seen_objects, match);
|
||||||
|
|
||||||
tree = &(match->children);
|
tree = &(match->children);
|
||||||
parent = match;
|
parent = match;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_ptr_array_free (seen_objects, TRUE);
|
g_ptr_array_free (seen_objects, TRUE);
|
||||||
|
|
||||||
len = nodes_to_unmark->len;
|
len = nodes_to_unmark->len;
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
@ -385,7 +385,7 @@ add_trace_to_tree (ProfileDescendant **tree, GList *trace, guint size)
|
|||||||
|
|
||||||
tree_node->marked_non_recursive = 0;
|
tree_node->marked_non_recursive = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = nodes_to_unmark_recursive->len;
|
len = nodes_to_unmark_recursive->len;
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
@ -393,7 +393,7 @@ add_trace_to_tree (ProfileDescendant **tree, GList *trace, guint size)
|
|||||||
|
|
||||||
tree_node->marked_total = FALSE;
|
tree_node->marked_total = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_ptr_array_free (nodes_to_unmark, TRUE);
|
g_ptr_array_free (nodes_to_unmark, TRUE);
|
||||||
g_ptr_array_free (nodes_to_unmark_recursive, TRUE);
|
g_ptr_array_free (nodes_to_unmark_recursive, TRUE);
|
||||||
}
|
}
|
||||||
@ -419,25 +419,25 @@ profile_create_descendants (Profile *profile,
|
|||||||
ProfileDescendant *tree = NULL;
|
ProfileDescendant *tree = NULL;
|
||||||
|
|
||||||
StackNode *node = stack_stash_find_node (profile->stash, object_name);
|
StackNode *node = stack_stash_find_node (profile->stash, object_name);
|
||||||
|
|
||||||
while (node)
|
while (node)
|
||||||
{
|
{
|
||||||
if (node->toplevel)
|
if (node->toplevel)
|
||||||
{
|
{
|
||||||
GList *leaves = NULL;
|
GList *leaves = NULL;
|
||||||
GList *list;
|
GList *list;
|
||||||
|
|
||||||
stack_node_list_leaves (node, &leaves);
|
stack_node_list_leaves (node, &leaves);
|
||||||
|
|
||||||
for (list = leaves; list != NULL; list = list->next)
|
for (list = leaves; list != NULL; list = list->next)
|
||||||
add_leaf_to_tree (&tree, list->data, node);
|
add_leaf_to_tree (&tree, list->data, node);
|
||||||
|
|
||||||
g_list_free (leaves);
|
g_list_free (leaves);
|
||||||
}
|
}
|
||||||
|
|
||||||
node = node->next;
|
node = node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,11 +460,11 @@ profile_list_callers (Profile *profile,
|
|||||||
GHashTable *callers_by_object;
|
GHashTable *callers_by_object;
|
||||||
GHashTable *seen_callers;
|
GHashTable *seen_callers;
|
||||||
ProfileCaller *result = NULL;
|
ProfileCaller *result = NULL;
|
||||||
|
|
||||||
callers_by_object =
|
callers_by_object =
|
||||||
g_hash_table_new (g_direct_hash, g_direct_equal);
|
g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
seen_callers = g_hash_table_new (g_direct_hash, g_direct_equal);
|
seen_callers = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||||
|
|
||||||
callee_node = stack_stash_find_node (profile->stash, callee_name);
|
callee_node = stack_stash_find_node (profile->stash, callee_name);
|
||||||
|
|
||||||
for (node = callee_node; node; node = node->next)
|
for (node = callee_node; node; node = node->next)
|
||||||
@ -530,7 +530,6 @@ profile_list_callers (Profile *profile,
|
|||||||
g_hash_table_destroy (callers_by_object);
|
g_hash_table_destroy (callers_by_object);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -567,17 +566,17 @@ build_object_list (StackNode *node, gpointer data)
|
|||||||
{
|
{
|
||||||
GList **objects = data;
|
GList **objects = data;
|
||||||
ProfileObject *obj;
|
ProfileObject *obj;
|
||||||
|
|
||||||
obj = g_new (ProfileObject, 1);
|
obj = g_new (ProfileObject, 1);
|
||||||
obj->name = node->address;
|
obj->name = node->address;
|
||||||
|
|
||||||
obj->total = compute_total (node);
|
obj->total = compute_total (node);
|
||||||
|
|
||||||
/* FIXME: this is incorrect. We need to sum all the node linked
|
/* FIXME: this is incorrect. We need to sum all the node linked
|
||||||
* through node->next
|
* through node->next
|
||||||
*/
|
*/
|
||||||
obj->self = node->size;
|
obj->self = node->size;
|
||||||
|
|
||||||
*objects = g_list_prepend (*objects, obj);
|
*objects = g_list_prepend (*objects, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,9 +584,9 @@ GList *
|
|||||||
profile_get_objects (Profile *profile)
|
profile_get_objects (Profile *profile)
|
||||||
{
|
{
|
||||||
GList *objects = NULL;
|
GList *objects = NULL;
|
||||||
|
|
||||||
stack_stash_foreach_by_address (profile->stash, build_object_list, &objects);
|
stack_stash_foreach_by_address (profile->stash, build_object_list, &objects);
|
||||||
|
|
||||||
/* FIXME: everybody still assumes that they don't have to free the
|
/* FIXME: everybody still assumes that they don't have to free the
|
||||||
* objects in the list, but these days they do, and so we are leaking.
|
* objects in the list, but these days they do, and so we are leaking.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user