12f39bdcb8c271a80621329a9e87878b696b5b2d
[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_SZARRAY:
78                         mono_field_get_value (obj, field, &value);
79
80                         if (value != NULL) {
81                                 total += memory_usage_array ((MonoArray *) value, visited);
82                                 total += mono_object_get_size ((MonoObject *) value);
83                         }
84
85                         break;
86
87                 default:
88                         /* printf ("Got type 0x%x\n", ftype->type); */
89                         /* ignore, this will be included in mono_object_get_size () */
90                         break;
91                 }
92         }
93
94         total += mono_object_get_size (obj);
95
96         return total;
97 }
98
99 /*
100  * Only returns data for instances, not for static fields, those might
101  * be larger, or hold larger structures
102  */
103 static int
104 GetMemoryUsage (MonoObject *this)
105 {
106         GHashTable *visited = g_hash_table_new (NULL, NULL);
107         int n;
108         
109         n = memory_usage (this, visited);
110
111         g_hash_table_destroy (visited);
112         
113         return n;
114 }
115
116 static int installed = 0;
117
118 void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result)
119 {
120         if (installed)
121                 return;
122
123         mono_add_internal_call ("Mono.ObjectServices.ObjectInspector::GetMemoryUsage", GetMemoryUsage);
124         installed = 1;
125 }
126
127 void
128 mono_profiler_startup (const char *desc)
129 {
130         mono_profiler_install_jit_end (install_icall);
131         mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION);
132 }