86ec27dfd6da4fe6942232aa351e4003c6283b5f
[mono.git] / samples / size / size.c
1 #include <glib.h>
2 #include <mono/jit/jit.h>
3 #include <mono/metadata/environment.h>
4 #include <mono/metadata/profiler.h>
5 #include <mono/metadata/tokentype.h>
6 #include <mono/metadata/debug-helpers.h>
7 #include <mono/metadata/assembly.h>
8 #include <string.h>
9
10 #define FIELD_ATTRIBUTE_STATIC 0x10
11 #define FIELD_ATTRIBUTE_HAS_FIELD_RVA 0x100
12
13 static int memory_usage (MonoObject *obj, GHashTable *visited);
14
15 static int
16 memory_usage_array (MonoArray *array, GHashTable *visited)
17 {
18         int total = 0;
19         MonoClass *array_class = mono_object_get_class ((MonoObject *) array);
20         MonoClass *element_class = mono_class_get_element_class (array_class);
21         MonoType *element_type = mono_class_get_type (element_class);
22
23         if (MONO_TYPE_IS_REFERENCE (element_type)) {
24                 int i;
25
26                 for (i = 0; i < mono_array_length (array); i++) {
27                         MonoObject *element = mono_array_get (array, gpointer, i);
28
29                         if (element != NULL)
30                                 total += memory_usage (element, visited);
31                 }
32         }
33
34         return total;
35 }
36
37 static int
38 memory_usage (MonoObject *obj, GHashTable *visited)
39 {
40         int total = 0;
41         MonoClass *klass;
42         MonoType *type;
43         gpointer iter = NULL;
44         MonoClassField *field;
45
46         if (g_hash_table_lookup (visited, obj))
47                 return 0;
48
49         g_hash_table_insert (visited, obj, obj);
50
51         klass = mono_object_get_class (obj);
52         type = mono_class_get_type (klass);
53
54         /* This is an array, so drill down into it */
55         if (type->type == MONO_TYPE_SZARRAY)
56                 total += memory_usage_array ((MonoArray *) obj, visited);
57
58         while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
59                 MonoType *ftype = mono_field_get_type (field);
60                 gpointer value;
61
62                 if ((ftype->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)) != 0)
63                         continue;
64
65                 /* FIXME: There are probably other types we need to drill down into */
66                 switch (ftype->type) {
67
68                 case MONO_TYPE_CLASS:
69                 case MONO_TYPE_OBJECT:
70                         mono_field_get_value (obj, field, &value);
71
72                         if (value != NULL)
73                                 total += memory_usage ((MonoObject *) value, visited);
74
75                         break;
76
77                 case MONO_TYPE_STRING:
78                         mono_field_get_value (obj, field, &value);
79                         if (value != NULL)
80                                 total += mono_object_get_size ((MonoObject *) value);
81                         break;
82
83                 case MONO_TYPE_SZARRAY:
84                         mono_field_get_value (obj, field, &value);
85
86                         if (value != NULL) {
87                                 total += memory_usage_array ((MonoArray *) value, visited);
88                                 total += mono_object_get_size ((MonoObject *) value);
89                         }
90
91                         break;
92
93                 default:
94                         /* printf ("Got type 0x%x\n", ftype->type); */
95                         /* ignore, this will be included in mono_object_get_size () */
96                         break;
97                 }
98         }
99
100         total += mono_object_get_size (obj);
101
102         return total;
103 }
104
105 /*
106  * Only returns data for instances, not for static fields, those might
107  * be larger, or hold larger structures
108  */
109 static int
110 GetMemoryUsage (MonoObject *this)
111 {
112         GHashTable *visited = g_hash_table_new (NULL, NULL);
113         int n;
114         
115         n = memory_usage (this, visited);
116
117         g_hash_table_destroy (visited);
118         
119         return n;
120 }
121
122 static int installed = 0;
123
124 void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo)
125 {
126         if (installed)
127                 return;
128
129         mono_add_internal_call ("Mono.ObjectServices.ObjectInspector::GetMemoryUsage", GetMemoryUsage);
130         installed = 1;
131 }
132
133 void
134 mono_profiler_init (const char *desc)
135 {
136         MonoProfilerHandle handle = mono_profiler_install (NULL);
137         mono_profiler_set_jit_done_callback (handle, install_icall);
138 }