[aot] Rewrite the AOT profiler. (#4176)
authorZoltan Varga <vargaz@gmail.com>
Mon, 9 Jan 2017 22:37:57 +0000 (17:37 -0500)
committerGitHub <noreply@github.com>
Mon, 9 Jan 2017 22:37:57 +0000 (17:37 -0500)
* [aot] Rewrite the AOT profiler.

The AOT profiler is used to collect the methods/instances used at runtime.
Usage:
* mono --profile=aot:output=out.aotprof <app>
* mono --aot=profile=out.aotprof <assembly>

The first command will run <app>, collecting the list of methods it uses into the out.aotprof file.
The second command passes the profile file to the AOT compiler to have it generate additional generic instances.

* [docs] Add a section for AOT profiling to the mono(1) man page.

* [build] Collect AOT profile info from building mscorlib in the build profile, and use it when aot-ing the csc assemblies.

* [runtime] Add missing mono-profiler-aot.h file.

* [runtime] Tidy up usage of MONO_PROFILER_API.

* [aot] Improve error handling in the aot profiler.

* [aot] Improve error handling, add more diagnostics.

man/mono.1
mcs/class/aot-compiler/Makefile
mcs/class/corlib/Makefile
mono/metadata/class-internals.h
mono/metadata/domain-internals.h
mono/metadata/domain.c
mono/mini/aot-compiler.c
mono/profiler/mono-profiler-aot.c
mono/profiler/mono-profiler-aot.h [new file with mode: 0644]
mono/utils/mono-compiler.h

index bea38842eb323c86ba7a479686ff95537cf1ac3a..ef13ea04f687662685e404f3aeaca950df961480 100644 (file)
@@ -853,6 +853,26 @@ The offsets displayed are IL offsets.
 .PP
 A more powerful coverage tool is available in the module `monocov'.
 See the monocov(1) man page for details.
+.SH AOT PROFILING
+You can improve startup performance by using the AOT profiler.
+.PP
+Typically the AOT compiler (\fBmono --aot\fR) will not generate code
+for generic instantiations.   To solve this, you can run Mono with the
+AOT profiler to find out all the generic instantiations that are used,
+and then instructing the AOT compiler to produce code for these.
+.PP
+This command will run the specified app.exe and produce the
+\fBout.aotprof\fR file with the data describing the generic
+instantiations that are needed:
+.nf
+       $ mono --profile=aot:output=out.aotprof app.exe
+.fi
+.PP
+Once you have this data, you can pass this to Mono's AOT compiler to
+instruct it to generate code for it:
+.nf
+       $ mono --aot=profile=out.aotprof
+.fi
 .SH DEBUGGING AIDS
 To debug managed applications, you can use the 
 .B mdb
index 505f91591ec507d73f2b151498bfa3ac0dba0329..bcf7c1ba5ba806fb913e8ee380b47029f4f7bad9 100644 (file)
@@ -40,29 +40,34 @@ LIBRARY_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION)
 
 ifndef SKIP_AOT
 
+profile_file=$(wildcard $(topdir)/class/lib/build/csc.aotprofile)
+ifneq ($(profile_file),)
+profile_arg=,profile=$(profile_file)
+endif
+
 ifdef PLATFORM_AOT_SUFFIX
 $(mcs_aot_image): $(mcs_exe) $(mscorlib_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version,outfile=$(mcs_aot_image) --debug $(mcs_exe) || cat $(PROFILE)_aot.log || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(mcs_aot_image) --debug $(mcs_exe) || cat $(PROFILE)_aot.log || (cat $(PROFILE)_aot.log; exit 1)
 
 $(csc_aot_image): $(csc_exe) $(mscorlib_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version,outfile=$(csc_aot_image) --debug $(csc_exe) || cat $(PROFILE)_aot.log || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_aot_image) --debug $(csc_exe) || cat $(PROFILE)_aot.log || (cat $(PROFILE)_aot.log; exit 1)
 
 $(mscorlib_aot_image): $(mscorlib_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version --debug $(mscorlib_dll) || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg) --debug $(mscorlib_dll) || (cat $(PROFILE)_aot.log; exit 1)
 
 # Disabled as it hits AOT too big limit
 $(csc_MC_image): $(csc_MC_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version,outfile=$(csc_MC_image) --debug $(csc_MC_dll) || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_MC_image) --debug $(csc_MC_dll) || (cat $(PROFILE)_aot.log; exit 1)
 
 # Disabled as it hits AOT too big limit
 $(csc_MCS_image): $(csc_MCS_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version,outfile=$(csc_MCS_image) --debug $(csc_MCS_dll) || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_MCS_image) --debug $(csc_MCS_dll) || (cat $(PROFILE)_aot.log; exit 1)
 
 $(csc_SRM_image): $(csc_SRM_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version,outfile=$(csc_SRM_image) --debug $(csc_SRM_dll) || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_SRM_image) --debug $(csc_SRM_dll) || (cat $(PROFILE)_aot.log; exit 1)
 
 $(csc_SCI_image): $(csc_SCI_dll) $(runtime_dep)
-       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version,outfile=$(csc_SCI_image) --debug $(csc_SCI_dll) || (cat $(PROFILE)_aot.log; exit 1)
+       $(Q_AOT) MONO_PATH='$(the_libdir)' > $(PROFILE)_aot.log 2>&1 $(RUNTIME) --aot=bind-to-runtime-version$(profile_arg),outfile=$(csc_SCI_image) --debug $(csc_SCI_dll) || (cat $(PROFILE)_aot.log; exit 1)
 
 ifdef ENABLE_AOT
 
index 4d40d3371252ddfd8514b5835d17f42b0de7633b..e466678a17f65294bab12f26c131e732dc731aba 100644 (file)
@@ -20,6 +20,10 @@ $(error Unknown framework version)
 endif
 endif
 
+ifeq ($(PROFILE),build)
+CSC_RUNTIME_FLAGS=--profile=aot:output=$(topdir)/class/lib/build/csc.aotprofile
+endif
+
 RESOURCE_STRINGS = ../referencesource/mscorlib/mscorlib.txt
 RESX_RESOURCE_STRING = ../../../external/corefx/src/System.ValueTuple/src/Resources/Strings.resx
 
index dab2cc743c9011ef0e6d2ce4828da1f9c4b6e6be..efb4c62874f58d543fbfcf3988b1d93064004d77 100644 (file)
@@ -999,16 +999,16 @@ mono_install_get_cached_class_info (MonoGetCachedClassInfo func);
 void
 mono_install_get_class_from_name (MonoGetClassFromName func);
 
-MonoGenericContext*
+MONO_PROFILER_API MonoGenericContext*
 mono_class_get_context (MonoClass *klass);
 
-MonoMethodSignature*
+MONO_PROFILER_API MonoMethodSignature*
 mono_method_signature_checked (MonoMethod *m, MonoError *err);
 
 MonoGenericContext*
 mono_method_get_context_general (MonoMethod *method, gboolean uninflated);
 
-MonoGenericContext*
+MONO_PROFILER_API MonoGenericContext*
 mono_method_get_context (MonoMethod *method);
 
 /* Used by monodis, thus cannot be MONO_INTERNAL */
@@ -1286,7 +1286,7 @@ MONO_API void mono_class_describe_statics (MonoClass* klass);
 /* method debugging functions, for use inside gdb */
 MONO_API void mono_method_print_code (MonoMethod *method);
 
-char *mono_signature_full_name (MonoMethodSignature *sig);
+MONO_PROFILER_API char *mono_signature_full_name (MonoMethodSignature *sig);
 
 /*Enum validation related functions*/
 MONO_API gboolean
@@ -1295,7 +1295,7 @@ mono_type_is_valid_enum_basetype (MonoType * type);
 MONO_API gboolean
 mono_class_is_valid_enum (MonoClass *klass);
 
-gboolean
+MONO_PROFILER_API gboolean
 mono_type_is_primitive (MonoType *type);
 
 MonoType *
index a083d1ccc88ce2614c34f77c3e3967aa0d25d274..5e8282ccdf6e5311e019ed78779511bffcf3ed06 100644 (file)
@@ -602,5 +602,7 @@ mono_context_init_checked (MonoDomain *domain, MonoError *error);
 gboolean
 mono_assembly_has_reference_assembly_attribute (MonoAssembly *assembly, MonoError *error);
 
+GPtrArray*
+mono_domain_get_assemblies (MonoDomain *domain, gboolean refonly);
 
 #endif /* __MONO_METADATA_DOMAIN_INTERNALS_H__ */
index 26ee185cac717347684b88535fa54ccf7b13c3db..76cfe9979db3b8498e9f195c71787832da9ed2d0 100644 (file)
@@ -2013,3 +2013,24 @@ mono_domain_unlock (MonoDomain *domain)
 {
        mono_locks_coop_release (&domain->lock, DomainLock);
 }
+
+GPtrArray*
+mono_domain_get_assemblies (MonoDomain *domain, gboolean refonly)
+{
+       GSList *tmp;
+       GPtrArray *assemblies;
+       MonoAssembly *ass;
+
+       assemblies = g_ptr_array_new ();
+       mono_domain_assemblies_lock (domain);
+       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
+               ass = (MonoAssembly *)tmp->data;
+               if (refonly != ass->ref_only)
+                       continue;
+               if (ass->corlib_internal)
+                       continue;
+               g_ptr_array_add (assemblies, ass);
+       }
+       mono_domain_assemblies_unlock (domain);
+       return assemblies;
+}
index 3b4470fc3c6472580602dbb2037dc710b60dda6e..b91dfaedb245b11461172e3fae477c04cbee5ee8 100644 (file)
@@ -55,6 +55,7 @@
 #include <mono/utils/mono-rand.h>
 #include <mono/utils/json.h>
 #include <mono/utils/mono-threads-coop.h>
+#include <mono/profiler/mono-profiler-aot.h>
 #include <mono/io-layer/io-layer.h>
 
 #include "aot-compiler.h"
 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
 
+typedef struct {
+       char *name;
+       MonoImage *image;
+} ImageProfileData;
+
+typedef struct ClassProfileData ClassProfileData;
+
+typedef struct {
+       int argc;
+       ClassProfileData **argv;
+       MonoGenericInst *inst;
+} GInstProfileData;
+
+struct ClassProfileData {
+       ImageProfileData *image;
+       char *ns, *name;
+       GInstProfileData *inst;
+       MonoClass *klass;
+};
+
+typedef struct {
+       ClassProfileData *klass;
+       int id;
+       char *name;
+       int param_count;
+       char *signature;
+       GInstProfileData *inst;
+       MonoMethod *method;
+} MethodProfileData;
+
+typedef struct {
+       GHashTable *images, *classes, *ginsts, *methods;
+} ProfileData;
+
 /* predefined values for static readonly fields without needed to run the .cctor */
 typedef struct _ReadOnlyValue ReadOnlyValue;
 struct _ReadOnlyValue {
@@ -114,6 +149,7 @@ typedef struct MonoAotOptions {
        char *outfile;
        char *llvm_outfile;
        char *data_outfile;
+       char *profile_file;
        gboolean save_temps;
        gboolean write_symbols;
        gboolean metadata_only;
@@ -274,6 +310,7 @@ typedef struct MonoAotCompile {
        int objc_selector_index, objc_selector_index_2;
        GPtrArray *objc_selectors;
        GHashTable *objc_selector_to_index;
+       ProfileData *profile_data;
        FILE *logfile;
        FILE *instances_logfile;
        FILE *data_outfile;
@@ -343,6 +380,9 @@ get_plt_entry_debug_sym (MonoAotCompile *acfg, MonoJumpInfo *ji, GHashTable *cac
 static void
 add_gsharedvt_wrappers (MonoAotCompile *acfg, MonoMethodSignature *sig, gboolean gsharedvt_in, gboolean gsharedvt_out);
 
+static void
+add_profile_instances (MonoAotCompile *acfg);
+
 static void
 aot_printf (MonoAotCompile *acfg, const gchar *format, ...)
 {
@@ -7181,6 +7221,8 @@ mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
                        opts->llvm_only = TRUE;
                } else if (str_begins_with (arg, "data-outfile=")) {
                        opts->data_outfile = g_strdup (arg + strlen ("data-outfile="));
+               } else if (str_begins_with (arg, "profile=")) {
+                       opts->profile_file = g_strdup (arg + strlen ("profile="));
                } else if (str_begins_with (arg, "help") || str_begins_with (arg, "?")) {
                        printf ("Supported options for --aot:\n");
                        printf ("    outfile=\n");
@@ -7852,95 +7894,6 @@ compile_thread_main (gpointer user_data)
 
        return 0;
 }
-
-static void
-load_profile_files (MonoAotCompile *acfg)
-{
-       FILE *infile;
-       char *tmp;
-       int file_index, res, method_index, i;
-       char ver [256];
-       guint32 token;
-       GList *unordered, *l;
-       gboolean found;
-
-       file_index = 0;
-       while (TRUE) {
-               tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%d", g_get_home_dir (), acfg->image->assembly_name, file_index);
-
-               if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR)) {
-                       g_free (tmp);
-                       break;
-               }
-
-               infile = fopen (tmp, "r");
-               g_assert (infile);
-
-               printf ("Using profile data file '%s'\n", tmp);
-               g_free (tmp);
-
-               file_index ++;
-
-               res = fscanf (infile, "%32s\n", ver);
-               if ((res != 1) || strcmp (ver, "#VER:2") != 0) {
-                       printf ("Profile file has wrong version or invalid.\n");
-                       fclose (infile);
-                       continue;
-               }
-
-               while (TRUE) {
-                       char name [1024];
-                       MonoMethodDesc *desc;
-                       MonoMethod *method;
-
-                       if (fgets (name, 1023, infile) == NULL)
-                               break;
-
-                       /* Kill the newline */
-                       if (strlen (name) > 0)
-                               name [strlen (name) - 1] = '\0';
-
-                       desc = mono_method_desc_new (name, TRUE);
-
-                       method = mono_method_desc_search_in_image (desc, acfg->image);
-
-                       if (method && mono_method_get_token (method)) {
-                               token = mono_method_get_token (method);
-                               method_index = mono_metadata_token_index (token) - 1;
-
-                               found = FALSE;
-                               for (i = 0; i < acfg->method_order->len; ++i) {
-                                       if (g_ptr_array_index (acfg->method_order, i) == GUINT_TO_POINTER (method_index)) {
-                                               found = TRUE;
-                                               break;
-                                       }
-                               }
-                               if (!found)
-                                       g_ptr_array_add (acfg->method_order, GUINT_TO_POINTER (method_index));
-                       } else {
-                               //printf ("No method found matching '%s'.\n", name);
-                       }
-               }
-               fclose (infile);
-       }
-
-       /* Add missing methods */
-       unordered = NULL;
-       for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
-               found = FALSE;
-               for (i = 0; i < acfg->method_order->len; ++i) {
-                       if (g_ptr_array_index (acfg->method_order, i) == GUINT_TO_POINTER (method_index)) {
-                               found = TRUE;
-                               break;
-                       }
-               }
-               if (!found)
-                       unordered = g_list_prepend (unordered, GUINT_TO_POINTER (method_index));
-       }
-       unordered = g_list_reverse (unordered);
-       for (l = unordered; l; l = l->next)
-               g_ptr_array_add (acfg->method_order, l->data);
-}
  
 /* Used by the LLVM backend */
 guint32
@@ -9931,7 +9884,7 @@ compile_methods (MonoAotCompile *acfg)
 
        /* Compile methods added by compile_method () or all methods if nthreads == 0 */
        for (i = methods_len; i < acfg->methods->len; ++i) {
-               /* This can new methods to acfg->methods */
+               /* This can add new methods to acfg->methods */
                compile_method (acfg, (MonoMethod *)g_ptr_array_index (acfg->methods, i));
        }
 }
@@ -10172,7 +10125,433 @@ compile_asm (MonoAotCompile *acfg)
        return 0;
 }
 
-static void init_got_info (GotInfo *info)
+static guint8
+profread_byte (FILE *infile)
+{
+       guint8 i;
+       int res;
+
+       res = fread (&i, 1, 1, infile);
+       g_assert (res == 1);
+       return i;
+}
+
+static int
+profread_int (FILE *infile)
+{
+       int i, res;
+
+       res = fread (&i, 4, 1, infile);
+       g_assert (res == 1);
+       return i;
+}
+
+static char*
+profread_string (FILE *infile)
+{
+       int len, res;
+       char buf [1024];
+       char *pbuf;
+
+       len = profread_int (infile);
+       if (len + 1 > 1024)
+               pbuf = g_malloc (len + 1);
+       else
+               pbuf = buf;
+       res = fread (pbuf, 1, len, infile);
+       g_assert (res == len);
+       pbuf [len] = '\0';
+       if (pbuf == buf)
+               return g_strdup (buf);
+       else
+               return pbuf;
+}
+
+static void
+load_profile_file (MonoAotCompile *acfg, char *filename)
+{
+       FILE *infile;
+       char buf [1024];
+       int res, len, version;
+       char magic [32];
+
+       infile = fopen (filename, "r");
+       if (!infile) {
+               fprintf (stderr, "Unable to open file '%s': %s.\n", filename, strerror (errno));
+               exit (1);
+       }
+
+       printf ("Using profile data file '%s'\n", filename);
+
+       sprintf (magic, AOT_PROFILER_MAGIC);
+       len = strlen (magic);
+       res = fread (buf, 1, len, infile);
+       magic [len] = '\0';
+       buf [len] = '\0';
+       if ((res != len) || strcmp (buf, magic) != 0) {
+               printf ("Profile file has wrong header: '%s'.\n", buf);
+               fclose (infile);
+               exit (1);
+       }
+       guint32 expected_version = (AOT_PROFILER_MAJOR_VERSION << 16) | AOT_PROFILER_MINOR_VERSION;
+       version = profread_int (infile);
+       if (version != expected_version) {
+               printf ("Profile file has wrong version 0x%4x, expected 0x%4x.\n", version, expected_version);
+               fclose (infile);
+               exit (1);
+       }
+
+       ProfileData *data = g_new0 (ProfileData, 1);
+       data->images = g_hash_table_new (NULL, NULL);
+       data->classes = g_hash_table_new (NULL, NULL);
+       data->ginsts = g_hash_table_new (NULL, NULL);
+       data->methods = g_hash_table_new (NULL, NULL);
+
+       while (TRUE) {
+               int type = profread_byte (infile);
+               int id = profread_int (infile);
+
+               if (type == AOTPROF_RECORD_NONE)
+                       break;
+
+               switch (type) {
+               case AOTPROF_RECORD_IMAGE: {
+                       ImageProfileData *idata = g_new0 (ImageProfileData, 1);
+                       idata->name = profread_string (infile);
+                       char *mvid = profread_string (infile);
+                       g_free (mvid);
+                       g_hash_table_insert (data->images, GINT_TO_POINTER (id), idata);
+                       break;
+               }
+               case AOTPROF_RECORD_GINST: {
+                       int i;
+                       int len = profread_int (infile);
+
+                       GInstProfileData *gdata = g_new0 (GInstProfileData, 1);
+                       gdata->argc = len;
+                       gdata->argv = g_new0 (ClassProfileData*, len);
+
+                       for (i = 0; i < len; ++i) {
+                               int class_id = profread_int (infile);
+
+                               gdata->argv [i] = g_hash_table_lookup (data->classes, GINT_TO_POINTER (class_id));
+                               g_assert (gdata->argv [i]);
+                       }
+                       g_hash_table_insert (data->ginsts, GINT_TO_POINTER (id), gdata);
+                       break;
+               }
+               case AOTPROF_RECORD_TYPE: {
+                       int type = profread_byte (infile);
+
+                       switch (type) {
+                       case MONO_TYPE_CLASS: {
+                               int image_id = profread_int (infile);
+                               int ginst_id = profread_int (infile);
+                               char *class_name = profread_string (infile);
+
+                               ImageProfileData *image = g_hash_table_lookup (data->images, GINT_TO_POINTER (image_id));
+                               g_assert (image);
+
+                               char *p = strrchr (class_name, '.');
+                               g_assert (p);
+                               *p = '\0';
+
+                               ClassProfileData *cdata = g_new0 (ClassProfileData, 1);
+                               cdata->image = image;
+                               cdata->ns = g_strdup (class_name);
+                               cdata->name = g_strdup (p + 1);
+
+                               if (ginst_id != -1) {
+                                       cdata->inst = g_hash_table_lookup (data->ginsts, GINT_TO_POINTER (ginst_id));
+                                       g_assert (cdata->inst);
+                               }
+                               g_free (class_name);
+
+                               g_hash_table_insert (data->classes, GINT_TO_POINTER (id), cdata);
+                               break;
+                       }
+#if 0
+                       case MONO_TYPE_SZARRAY: {
+                               int elem_id = profread_int (infile);
+                               // FIXME:
+                               break;
+                       }
+#endif
+                       default:
+                               g_assert_not_reached ();
+                               break;
+                       }
+                       break;
+               }
+               case AOTPROF_RECORD_METHOD: {
+                       int class_id = profread_int (infile);
+                       int ginst_id = profread_int (infile);
+                       int param_count = profread_int (infile);
+                       char *method_name = profread_string (infile);
+                       char *sig = profread_string (infile);
+
+                       ClassProfileData *klass = g_hash_table_lookup (data->classes, GINT_TO_POINTER (class_id));
+                       g_assert (klass);
+
+                       MethodProfileData *mdata = g_new0 (MethodProfileData, 1);
+                       mdata->id = id;
+                       mdata->klass = klass;
+                       mdata->name = method_name;
+                       mdata->signature = sig;
+                       mdata->param_count = param_count;
+
+                       if (ginst_id != -1) {
+                               mdata->inst = g_hash_table_lookup (data->ginsts, GINT_TO_POINTER (ginst_id));
+                               g_assert (mdata->inst);
+                       }
+                       g_hash_table_insert (data->methods, GINT_TO_POINTER (id), mdata);
+                       break;
+               }
+               default:
+                       printf ("%d\n", type);
+                       g_assert_not_reached ();
+                       break;
+               }
+       }
+
+       acfg->profile_data = data;
+}
+
+static void
+resolve_class (ClassProfileData *cdata);
+
+static void
+resolve_ginst (GInstProfileData *inst_data)
+{
+       int i;
+
+       if (inst_data->inst)
+               return;
+
+       for (i = 0; i < inst_data->argc; ++i) {
+               resolve_class (inst_data->argv [i]);
+               if (!inst_data->argv [i]->klass)
+                       return;
+       }
+       MonoType **args = g_new0 (MonoType*, inst_data->argc);
+       for (i = 0; i < inst_data->argc; ++i)
+               args [i] = &inst_data->argv [i]->klass->byval_arg;
+
+       inst_data->inst = mono_metadata_get_generic_inst (inst_data->argc, args);
+}
+
+static void
+resolve_class (ClassProfileData *cdata)
+{
+       MonoError error;
+       MonoClass *klass;
+
+       if (!cdata->image->image)
+               return;
+
+       klass = mono_class_from_name_checked (cdata->image->image, cdata->ns, cdata->name, &error);
+       if (!klass) {
+               //printf ("[%s] %s.%s\n", cdata->image->name, cdata->ns, cdata->name);
+               return;
+       }
+       if (cdata->inst) {
+               resolve_ginst (cdata->inst);
+               if (!cdata->inst->inst)
+                       return;
+               MonoGenericContext ctx;
+
+               memset (&ctx, 0, sizeof (ctx));
+               ctx.class_inst = cdata->inst->inst;
+               cdata->klass = mono_class_inflate_generic_class_checked (klass, &ctx, &error);
+       } else {
+               cdata->klass = klass;
+       }
+}
+
+/*
+ * Resolve the profile data to the corresponding loaded classes/methods etc. if possible.
+ */
+static void
+resolve_profile_data (MonoAotCompile *acfg)
+{
+       ProfileData *data = acfg->profile_data;
+       GHashTableIter iter;
+       gpointer key, value;
+       int i;
+
+       if (!data)
+               return;
+
+       /* Images */
+       GPtrArray *assemblies = mono_domain_get_assemblies (mono_get_root_domain (), FALSE);
+       g_hash_table_iter_init (&iter, data->images);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ImageProfileData *idata = (ImageProfileData*)value;
+
+               for (i = 0; i < assemblies->len; ++i) {
+                       MonoAssembly *ass = g_ptr_array_index (assemblies, i);
+
+                       if (!strcmp (ass->aname.name, idata->name)) {
+                               idata->image = ass->image;
+                               break;
+                       }
+               }
+       }
+       g_ptr_array_free (assemblies, TRUE);
+
+       /* Classes */
+       g_hash_table_iter_init (&iter, data->classes);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ClassProfileData *cdata = (ClassProfileData*)value;
+
+               if (!cdata->image->image)
+                       continue;
+
+               resolve_class (cdata);
+               /*
+               if (cdata->klass)
+                       printf ("%s %s %s\n", cdata->ns, cdata->name, mono_class_full_name (cdata->klass));
+               */
+       }
+
+       /* Methods */
+       g_hash_table_iter_init (&iter, data->methods);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               MethodProfileData *mdata = (MethodProfileData*)value;
+               MonoClass *klass;
+               MonoMethod *m;
+               gpointer miter;
+
+               resolve_class (mdata->klass);
+               klass = mdata->klass->klass;
+               if (!klass)
+                       continue;
+               miter = NULL;
+               while ((m = mono_class_get_methods (klass, &miter))) {
+                       MonoError error;
+
+                       if (strcmp (m->name, mdata->name))
+                               continue;
+                       MonoMethodSignature *sig = mono_method_signature (m);
+                       if (!sig)
+                               continue;
+                       if (sig->param_count != mdata->param_count)
+                               continue;
+                       if (mdata->inst) {
+                               resolve_ginst (mdata->inst);
+                               if (!mdata->inst->inst)
+                                       continue;
+                               MonoGenericContext ctx;
+
+                               memset (&ctx, 0, sizeof (ctx));
+                               ctx.method_inst = mdata->inst->inst;
+
+                               m = mono_class_inflate_generic_method_checked (m, &ctx, &error);
+                               if (!m)
+                                       continue;
+                               sig = mono_method_signature_checked (m, &error);
+                               if (!is_ok (&error)) {
+                                       mono_error_cleanup (&error);
+                                       continue;
+                               }
+                       }
+                       char *sig_str = mono_signature_full_name (sig);
+                       gboolean match = !strcmp (sig_str, mdata->signature);
+                       g_free (sig_str);
+                       if (!match)
+                               continue;
+                       //printf ("%s\n", mono_method_full_name (m, 1));
+                       mdata->method = m;
+                       break;
+               }
+       }
+}
+
+static gboolean
+inst_references_image (MonoGenericInst *inst, MonoImage *image)
+{
+       int i;
+
+       for (i = 0; i < inst->type_argc; ++i) {
+               MonoClass *k = mono_class_from_mono_type (inst->type_argv [i]);
+               if (k->image == image)
+                       return TRUE;
+               if (mono_class_is_ginst (k)) {
+                       MonoGenericInst *kinst = mono_class_get_context (k)->class_inst;
+                       if (inst_references_image (kinst, image))
+                               return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+static gboolean
+is_local_inst (MonoGenericInst *inst, MonoImage *image)
+{
+       int i;
+
+       for (i = 0; i < inst->type_argc; ++i) {
+               MonoClass *k = mono_class_from_mono_type (inst->type_argv [i]);
+               if (!MONO_TYPE_IS_PRIMITIVE (inst->type_argv [i]) && k->image != image)
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+static void
+add_profile_instances (MonoAotCompile *acfg)
+{
+       ProfileData *data = acfg->profile_data;
+       GHashTableIter iter;
+       gpointer key, value;
+       int count = 0;
+
+       if (!data)
+               return;
+
+       /*
+        * Add method instances 'related' to this assembly to the AOT image.
+        */
+       g_hash_table_iter_init (&iter, data->methods);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               MethodProfileData *mdata = (MethodProfileData*)value;
+               MonoMethod *m = mdata->method;
+               MonoGenericContext *ctx;
+
+               if (!m)
+                       continue;
+               if (!m->is_inflated)
+                       continue;
+
+               ctx = mono_method_get_context (m);
+               /* For simplicity, add instances which reference the assembly we are compiling */
+               if (((ctx->class_inst && inst_references_image (ctx->class_inst, acfg->image)) ||
+                        (ctx->method_inst && inst_references_image (ctx->method_inst, acfg->image))) &&
+                       !mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE)) {
+                       //printf ("%s\n", mono_method_full_name (m, TRUE));
+                       add_extra_method (acfg, m);
+                       count ++;
+               } else if (m->klass->image == acfg->image &&
+                       ((ctx->class_inst && is_local_inst (ctx->class_inst, acfg->image)) ||
+                        (ctx->method_inst && is_local_inst (ctx->method_inst, acfg->image))) &&
+                       !mono_method_is_generic_sharable_full (m, FALSE, FALSE, FALSE))  {
+                       /* Add instances where the gtd is in the assembly and its inflated with types from this assembly or corlib */
+                       //printf ("%s\n", mono_method_full_name (m, TRUE));
+                       add_extra_method (acfg, m);
+                       count ++;
+               }
+               /*
+                * FIXME: We might skip some instances, for example:
+                * Foo<Bar> won't be compiled when compiling Foo's assembly since it doesn't match the first case,
+                * and it won't be compiled when compiling Bar's assembly if Foo's assembly is not loaded.
+                */
+       }
+
+       printf ("Added %d methods from profile.\n", count);
+}
+
+static void
+init_got_info (GotInfo *info)
 {
        int i;
 
@@ -10652,7 +11031,16 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
                }
        }
 
-       load_profile_files (acfg);
+       if (acfg->aot_opts.profile_file)
+               load_profile_file (acfg, acfg->aot_opts.profile_file);
+
+       {
+               int method_index;
+
+       for (method_index = 0; method_index < acfg->image->tables [MONO_TABLE_METHOD].rows; ++method_index) {
+                  g_ptr_array_add (acfg->method_order,GUINT_TO_POINTER (method_index));
+       }
+       }
 
        acfg->num_trampolines [MONO_AOT_TRAMP_SPECIFIC] = mono_aot_mode_is_full (&acfg->aot_opts) ? acfg->aot_opts.ntrampolines : 0;
 #ifdef MONO_ARCH_GSHARED_SUPPORTED
@@ -10713,6 +11101,10 @@ mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
        if (!res)
                return 1;
 
+       resolve_profile_data (acfg);
+
+       add_profile_instances (acfg);
+
        acfg->cfgs_size = acfg->methods->len + 32;
        acfg->cfgs = g_new0 (MonoCompile*, acfg->cfgs_size);
 
index 4cf48bbd1b2491a54e3155c2c793b1934d5bb441..05ed0758ed2cfff00dea1280523e4e3abc7495c9 100644 (file)
  */
 
 #include <config.h>
+
+#include "mono-profiler-aot.h"
+
 #include <mono/metadata/profiler.h>
 #include <mono/metadata/tokentype.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/assembly.h>
+#include <mono/metadata/class-internals.h>
+#include <mono/utils/mono-os-mutex.h>
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
 #endif
 
 struct _MonoProfiler {
+       GHashTable *classes;
        GHashTable *images;
+       GPtrArray *methods;
+       FILE *outfile;
+       int id;
+       char *outfile_name;
 };
 
-typedef struct {
-       GList *methods;
-} PerImageData;
+static mono_mutex_t mutex;
+static gboolean verbose;
 
-typedef struct ForeachData {
-       MonoProfiler *prof;
-       FILE *outfile;
-       MonoImage *image;
-       MonoMethod *method;
-} ForeachData;
+static void
+prof_jit_enter (MonoProfiler *prof, MonoMethod *method)
+{
+}
 
 static void
-foreach_method (gpointer data, gpointer user_data)
+prof_jit_leave (MonoProfiler *prof, MonoMethod *method, int result)
 {
-       ForeachData *udata = (ForeachData*)user_data;
-       MonoMethod *method = (MonoMethod*)data;
-       char *name;
+       MonoImage *image = mono_class_get_image (mono_method_get_class (method));
 
-       if (!mono_method_get_token (method) || mono_class_get_image (mono_method_get_class (method)) != udata->image)
+       if (!image->assembly || method->wrapper_type)
                return;
 
-       name = mono_method_full_name (method, TRUE);
-       fprintf (udata->outfile, "%s\n", name);
-       g_free (name);
+       mono_os_mutex_lock (&mutex);
+       g_ptr_array_add (prof->methods, method);
+       mono_os_mutex_unlock (&mutex);
 }
 
 static void
-output_image (gpointer key, gpointer value, gpointer user_data)
-{
-       MonoImage *image = (MonoImage*)key;
-       PerImageData *image_data = (PerImageData*)value;
-       MonoProfiler *prof = (MonoProfiler*)user_data;
-       char *tmp, *outfile_name;
-       FILE *outfile;
-       int i, err;
-       ForeachData data;
+prof_shutdown (MonoProfiler *prof);
 
-       tmp = g_strdup_printf ("%s/.mono/aot-profile-data", g_get_home_dir ());
+static void
+usage (int do_exit)
+{
+       printf ("AOT profiler.\n");
+       printf ("Usage: mono --profile=aot[:OPTION1[,OPTION2...]] program.exe\n");
+       printf ("Options:\n");
+       printf ("\thelp                 show this usage info\n");
+       printf ("\toutput=FILENAME      write the data to file FILENAME (required)\n");
+       printf ("\tverbose              print diagnostic info\n");
+       if (do_exit)
+               exit (1);
+}
 
-       if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
-#ifdef HOST_WIN32
-               err = mkdir (tmp);
-#else
-               err = mkdir (tmp, 0777);
-#endif
-               if (err) {
-                       fprintf (stderr, "mono-profiler-aot: Unable to create output directory '%s': %s\n", tmp, g_strerror (errno));
-                       exit (1);
+static const char*
+match_option (const char* p, const char *opt, char **rval)
+{
+       int len = strlen (opt);
+       if (strncmp (p, opt, len) == 0) {
+               if (rval) {
+                       if (p [len] == '=' && p [len + 1]) {
+                               const char *opt = p + len + 1;
+                               const char *end = strchr (opt, ',');
+                               char *val;
+                               int l;
+                               if (end == NULL) {
+                                       l = strlen (opt);
+                               } else {
+                                       l = end - opt;
+                               }
+                               val = (char *) g_malloc (l + 1);
+                               memcpy (val, opt, l);
+                               val [l] = 0;
+                               *rval = val;
+                               return opt + l;
+                       }
+                       if (p [len] == 0 || p [len] == ',') {
+                               *rval = NULL;
+                               return p + len + (p [len] == ',');
+                       }
+                       usage (1);
+               } else {
+                       if (p [len] == 0)
+                               return p + len;
+                       if (p [len] == ',')
+                               return p + len + 1;
                }
        }
+       return p;
+}
 
-       i = 0;
-       while (TRUE) {
-               outfile_name = g_strdup_printf ("%s/%s-%d", tmp, mono_image_get_name (image), i);
+void
+mono_profiler_startup (const char *desc);
 
-               if (!g_file_test (outfile_name, G_FILE_TEST_IS_REGULAR))
-                       break;
+/* the entry point */
+void
+mono_profiler_startup (const char *desc)
+{
+       MonoProfiler *prof;
+       const char *p;
+       const char *opt;
+       char *outfile_name;
 
-               i ++;
+       p = desc;
+       if (strncmp (p, "aot", 3))
+               usage (1);
+       p += 3;
+       if (*p == ':')
+               p++;
+       for (; *p; p = opt) {
+               char *val;
+               if (*p == ',') {
+                       opt = p + 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "help", NULL)) != p) {
+                       usage (0);
+                       continue;
+               }
+               if ((opt = match_option (p, "verbose", NULL)) != p) {
+                       verbose = TRUE;
+                       continue;
+               }
+               if ((opt = match_option (p, "output", &val)) != p) {
+                       outfile_name = val;
+                       continue;
+               }
+               fprintf (stderr, "mono-profiler-aot: Unknown option: '%s'.\n", p);
+               exit (1);
        }
 
-       printf ("Creating output file: %s\n", outfile_name);
+       if (!outfile_name) {
+               fprintf (stderr, "mono-profiler-aot: The 'output' argument is required.\n");
+               exit (1);
+       }
 
-       outfile = fopen (outfile_name, "w+");
-       g_assert (outfile);
+       prof = g_new0 (MonoProfiler, 1);
+       prof->images = g_hash_table_new (NULL, NULL);
+       prof->classes = g_hash_table_new (NULL, NULL);
+       prof->methods = g_ptr_array_new ();
+       prof->outfile_name = outfile_name;
+
+       mono_os_mutex_init (&mutex);
 
-       fprintf (outfile, "#VER:%d\n", 2);
+       mono_profiler_install (prof, prof_shutdown);
+
+       mono_profiler_install_jit_compile (prof_jit_enter, prof_jit_leave);
 
-       data.prof = prof;
-       data.outfile = outfile;
-       data.image = image;
+       mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION);
+}
 
-       g_list_foreach (image_data->methods, foreach_method, &data);
+static void
+emit_byte (MonoProfiler *prof, guint8 value)
+{
+       fwrite (&value, 1, 1, prof->outfile);
 }
 
-/* called at the end of the program */
 static void
-prof_shutdown (MonoProfiler *prof)
+emit_int32 (MonoProfiler *prof, int value)
 {
-       g_hash_table_foreach (prof->images, output_image, prof);
+       // FIXME: Endianness
+       fwrite (&value, 4, 1, prof->outfile);
 }
 
 static void
-prof_jit_enter (MonoProfiler *prof, MonoMethod *method)
+emit_string (MonoProfiler *prof, const char *str)
 {
+       int len = strlen (str);
+
+       emit_int32 (prof, len);
+       fwrite (str, len, 1, prof->outfile);
 }
 
 static void
-prof_jit_leave (MonoProfiler *prof, MonoMethod *method, int result)
+emit_record (MonoProfiler *prof, AotProfRecordType type, int id)
 {
-       MonoImage *image = mono_class_get_image (mono_method_get_class (method));
-       PerImageData *data;
+       emit_byte (prof, type);
+       emit_int32 (prof, id);
+}
+
+static int
+add_image (MonoProfiler *prof, MonoImage *image)
+{
+       int id = GPOINTER_TO_INT (g_hash_table_lookup (prof->images, image));
+       if (id)
+               return id - 1;
 
-       data = (PerImageData *)g_hash_table_lookup (prof->images, image);
-       if (!data) {
-               data = g_new0 (PerImageData, 1);
-               g_hash_table_insert (prof->images, image, data);
+       id = prof->id ++;
+       emit_record (prof, AOTPROF_RECORD_IMAGE, id);
+       emit_string (prof, image->assembly->aname.name);
+       emit_string (prof, image->guid);
+       g_hash_table_insert (prof->images, image, GINT_TO_POINTER (id + 1));
+       return id;
+}
+
+static int
+add_class (MonoProfiler *prof, MonoClass *klass);
+
+static int
+add_type (MonoProfiler *prof, MonoType *type)
+{
+       switch (type->type) {
+#if 0
+       case MONO_TYPE_SZARRAY: {
+               int eid = add_type (prof, &type->data.klass->byval_arg);
+               if (eid == -1)
+                       return -1;
+               int id = prof->id ++;
+               emit_record (prof, AOTPROF_RECORD_TYPE, id);
+               emit_byte (prof, MONO_TYPE_SZARRAY);
+               emit_int32 (prof, id);
+               return id;
+       }
+#endif
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+       case MONO_TYPE_R4:
+       case MONO_TYPE_R8:
+       case MONO_TYPE_I:
+       case MONO_TYPE_U:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_VALUETYPE:
+       case MONO_TYPE_GENERICINST:
+               return add_class (prof, mono_class_from_mono_type (type));
+       default:
+               return -1;
+       }
+}
+
+static int
+add_ginst (MonoProfiler *prof, MonoGenericInst *inst)
+{
+       int i, id;
+       int *ids;
+
+       // FIXME: Cache
+       ids = g_malloc0 (inst->type_argc * sizeof (int));
+       for (i = 0; i < inst->type_argc; ++i) {
+               MonoType *t = inst->type_argv [i];
+               ids [i] = add_type (prof, t);
+               if (ids [i] == -1) {
+                       g_free (ids);
+                       return -1;
+               }
        }
+       id = prof->id ++;
+       emit_record (prof, AOTPROF_RECORD_GINST, id);
+       emit_int32 (prof, inst->type_argc);
+       for (i = 0; i < inst->type_argc; ++i)
+               emit_int32 (prof, ids [i]);
+       g_free (ids);
 
-       data->methods = g_list_append (data->methods, method);
+       return id;
 }
 
-void
-mono_profiler_startup (const char *desc);
+static int
+add_class (MonoProfiler *prof, MonoClass *klass)
+{
+       int id, inst_id = -1, image_id;
+       char *name;
 
-/* the entry point */
-void
-mono_profiler_startup (const char *desc)
+       id = GPOINTER_TO_INT (g_hash_table_lookup (prof->classes, klass));
+       if (id)
+               return id - 1;
+
+       image_id = add_image (prof, klass->image);
+
+       if (mono_class_is_ginst (klass)) {
+               MonoGenericContext *ctx = mono_class_get_context (klass);
+               inst_id = add_ginst (prof, ctx->class_inst);
+               if (inst_id == -1)
+                       return -1;
+       }
+
+       if (klass->nested_in)
+               name = g_strdup_printf ("%s.%s/%s", klass->nested_in->name_space, klass->nested_in->name, klass->name);
+       else
+               name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
+
+       id = prof->id ++;
+       emit_record (prof, AOTPROF_RECORD_TYPE, id);
+       emit_byte (prof, MONO_TYPE_CLASS);
+       emit_int32 (prof, image_id);
+       emit_int32 (prof, inst_id);
+       emit_string (prof, name);
+       g_free (name);
+       g_hash_table_insert (prof->classes, klass, GINT_TO_POINTER (id + 1));
+       return id;
+}
+
+static void
+add_method (MonoProfiler *prof, MonoMethod *m)
 {
-       MonoProfiler *prof;
+       MonoError error;
+       MonoMethodSignature *sig;
+       char *s;
 
-       prof = g_new0 (MonoProfiler, 1);
-       prof->images = g_hash_table_new (NULL, NULL);
+       sig = mono_method_signature_checked (m, &error);
+       g_assert (mono_error_ok (&error));
 
-       mono_profiler_install (prof, prof_shutdown);
-       
-       mono_profiler_install_jit_compile (prof_jit_enter, prof_jit_leave);
+       int class_id = add_class (prof, m->klass);
+       if (class_id == -1)
+               return;
+       int inst_id = -1;
 
-       mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION);
+       if (m->is_inflated) {
+               MonoGenericContext *ctx = mono_method_get_context (m);
+               if (ctx->method_inst)
+                       inst_id = add_ginst (prof, ctx->method_inst);
+       }
+       int id = prof->id ++;
+       emit_record (prof, AOTPROF_RECORD_METHOD, id);
+       emit_int32 (prof, class_id);
+       emit_int32 (prof, inst_id);
+       emit_int32 (prof, sig->param_count);
+       emit_string (prof, m->name);
+       s = mono_signature_full_name (sig);
+       emit_string (prof, s);
+       g_free (s);
+       if (verbose)
+               printf ("%s %d\n", mono_method_full_name (m, 1), id);
 }
 
+/* called at the end of the program */
+static void
+prof_shutdown (MonoProfiler *prof)
+{
+       FILE *outfile;
+       int mindex;
+       char magic [32];
+
+       printf ("Creating output file: %s\n", prof->outfile_name);
+
+       outfile = fopen (prof->outfile_name, "w+");
+       if (!outfile) {
+               fprintf (stderr, "Unable to create output file '%s': %s.\n", prof->outfile_name, strerror (errno));
+               return;
+       }
+       prof->outfile = outfile;
+
+       gint32 version = (AOT_PROFILER_MAJOR_VERSION << 16) | AOT_PROFILER_MINOR_VERSION;
+       sprintf (magic, AOT_PROFILER_MAGIC);
+       fwrite (magic, strlen (magic), 1, outfile);
+       emit_int32 (prof, version);
+
+       GHashTable *all_methods = g_hash_table_new (NULL, NULL);
+       for (mindex = 0; mindex < prof->methods->len; ++mindex) {
+           MonoMethod *m = (MonoMethod*)g_ptr_array_index (prof->methods, mindex);
 
+               if (!mono_method_get_token (m))
+                       continue;
+
+               if (g_hash_table_lookup (all_methods, m))
+                       continue;
+               g_hash_table_insert (all_methods, m, m);
+
+               add_method (prof, m);
+       }
+       emit_record (prof, AOTPROF_RECORD_NONE, 0);
+
+       fclose (outfile);
+
+       g_hash_table_destroy (all_methods);
+       g_hash_table_destroy (prof->classes);
+       g_hash_table_destroy (prof->images);
+       g_ptr_array_free (prof->methods, TRUE);
+       g_free (prof->outfile_name);
+}
diff --git a/mono/profiler/mono-profiler-aot.h b/mono/profiler/mono-profiler-aot.h
new file mode 100644 (file)
index 0000000..7663cab
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __MONO_PROFILER_AOT_H__
+#define __MONO_PROFILER_AOT_H__
+
+#include <config.h>
+
+/*
+ * File format:
+ * - magic
+ * - major/minor version as an int, i.e. 0x00010001
+ * - sequence of records terminated by a record with type TYPE_NONE
+ * Record format:
+ * - 1 byte record type (AotProfRecordType)
+ * - 1 int record id
+ * - record specific data
+ * Encoding rules:
+ * - int - 4 bytes little endian
+ * - string - int length followed by data
+ */
+
+typedef enum {
+       AOTPROF_RECORD_NONE,
+       AOTPROF_RECORD_IMAGE,
+       AOTPROF_RECORD_TYPE,
+       AOTPROF_RECORD_GINST,
+       AOTPROF_RECORD_METHOD
+} AotProfRecordType;
+
+#define AOT_PROFILER_MAGIC "AOTPROFILE"
+
+#define AOT_PROFILER_MAJOR_VERSION 1
+#define AOT_PROFILER_MINOR_VERSION 0
+
+#endif /* __MONO_PROFILER_AOT_H__ */
index 2a7849f101afb6bea053aa99b3715755987ab662..8d83f5d672e2cae2bc7ed2a9099c42e9c0599016 100644 (file)
@@ -80,6 +80,9 @@ typedef SSIZE_T ssize_t;
 #define MONO_LLVM_INTERNAL 
 #endif
 
+/* Used to mark internal functions used by the profiler modules */
+#define MONO_PROFILER_API MONO_API
+
 #ifdef __GNUC__
 #define MONO_ALWAYS_INLINE __attribute__((always_inline))
 #elif defined(_MSC_VER)