size.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. #define FIELD_ATTRIBUTE_STATIC 0x10
  10. #define FIELD_ATTRIBUTE_HAS_FIELD_RVA 0x100
  11. static int memory_usage (MonoObject *obj, GHashTable *visited);
  12. static int
  13. memory_usage_array (MonoArray *array, GHashTable *visited)
  14. {
  15. int total = 0;
  16. MonoClass *array_class = mono_object_get_class ((MonoObject *) array);
  17. MonoClass *element_class = mono_class_get_element_class (array_class);
  18. MonoType *element_type = mono_class_get_type (element_class);
  19. if (MONO_TYPE_IS_REFERENCE (element_type)) {
  20. int i;
  21. for (i = 0; i < mono_array_length (array); i++) {
  22. MonoObject *element = mono_array_get (array, gpointer, i);
  23. if (element != NULL)
  24. total += memory_usage (element, visited);
  25. }
  26. }
  27. return total;
  28. }
  29. static int
  30. memory_usage (MonoObject *obj, GHashTable *visited)
  31. {
  32. int total = 0;
  33. MonoClass *klass;
  34. MonoType *type;
  35. gpointer iter = NULL;
  36. MonoClassField *field;
  37. if (g_hash_table_lookup (visited, obj))
  38. return 0;
  39. g_hash_table_insert (visited, obj, obj);
  40. klass = mono_object_get_class (obj);
  41. type = mono_class_get_type (klass);
  42. /* This is an array, so drill down into it */
  43. if (type->type == MONO_TYPE_SZARRAY)
  44. total += memory_usage_array ((MonoArray *) obj, visited);
  45. while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
  46. MonoType *ftype = mono_field_get_type (field);
  47. gpointer value;
  48. if ((ftype->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)) != 0)
  49. continue;
  50. /* FIXME: There are probably other types we need to drill down into */
  51. switch (ftype->type) {
  52. case MONO_TYPE_CLASS:
  53. case MONO_TYPE_OBJECT:
  54. mono_field_get_value (obj, field, &value);
  55. if (value != NULL)
  56. total += memory_usage ((MonoObject *) value, visited);
  57. break;
  58. case MONO_TYPE_STRING:
  59. mono_field_get_value (obj, field, &value);
  60. if (value != NULL)
  61. total += mono_object_get_size ((MonoObject *) value);
  62. break;
  63. case MONO_TYPE_SZARRAY:
  64. mono_field_get_value (obj, field, &value);
  65. if (value != NULL) {
  66. total += memory_usage_array ((MonoArray *) value, visited);
  67. total += mono_object_get_size ((MonoObject *) value);
  68. }
  69. break;
  70. default:
  71. /* printf ("Got type 0x%x\n", ftype->type); */
  72. /* ignore, this will be included in mono_object_get_size () */
  73. break;
  74. }
  75. }
  76. total += mono_object_get_size (obj);
  77. return total;
  78. }
  79. /*
  80. * Only returns data for instances, not for static fields, those might
  81. * be larger, or hold larger structures
  82. */
  83. static int
  84. GetMemoryUsage (MonoObject *this)
  85. {
  86. GHashTable *visited = g_hash_table_new (NULL, NULL);
  87. int n;
  88. n = memory_usage (this, visited);
  89. g_hash_table_destroy (visited);
  90. return n;
  91. }
  92. static int installed = 0;
  93. void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result)
  94. {
  95. if (installed)
  96. return;
  97. mono_add_internal_call ("Mono.ObjectServices.ObjectInspector::GetMemoryUsage", GetMemoryUsage);
  98. installed = 1;
  99. }
  100. void
  101. mono_profiler_startup (const char *desc)
  102. {
  103. mono_profiler_install_jit_end (install_icall);
  104. mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION);
  105. }