2 * aot.c: Ahead of Time Compiler Profiler for Mono.
5 * Copyright 2008-2009 Novell, Inc (http://www.novell.com)
7 * This profiler collects profiling information usable by the Mono AOT compiler
8 * to generate better code. It saves the information into files under ~/.mono.
9 * The AOT compiler can load these files during compilation.
10 * Currently, only the order in which methods were compiled is saved,
11 * allowing more efficient function ordering in the AOT files.
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
19 #include <mono/metadata/profiler.h>
20 #include <mono/metadata/tokentype.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/debug-helpers.h>
23 #include <mono/metadata/assembly.h>
24 #include <mono/metadata/class-internals.h>
25 #include <mono/utils/mono-os-mutex.h>
36 struct _MonoProfiler {
45 static mono_mutex_t mutex;
46 static gboolean verbose;
49 prof_jit_leave (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
51 MonoImage *image = mono_class_get_image (mono_method_get_class (method));
53 if (!image->assembly || method->wrapper_type)
56 mono_os_mutex_lock (&mutex);
57 g_ptr_array_add (prof->methods, method);
58 mono_os_mutex_unlock (&mutex);
62 prof_shutdown (MonoProfiler *prof);
67 printf ("AOT profiler.\n");
68 printf ("Usage: mono --profile=aot[:OPTION1[,OPTION2...]] program.exe\n");
69 printf ("Options:\n");
70 printf ("\thelp show this usage info\n");
71 printf ("\toutput=FILENAME write the data to file FILENAME (required)\n");
72 printf ("\tverbose print diagnostic info\n");
78 match_option (const char* p, const char *opt, char **rval)
80 int len = strlen (opt);
81 if (strncmp (p, opt, len) == 0) {
83 if (p [len] == '=' && p [len + 1]) {
84 const char *opt = p + len + 1;
85 const char *end = strchr (opt, ',');
93 val = (char *) g_malloc (l + 1);
99 if (p [len] == 0 || p [len] == ',') {
101 return p + len + (p [len] == ',');
115 mono_profiler_init_aot (const char *desc);
118 * mono_profiler_init_aot:
122 mono_profiler_init_aot (const char *desc)
127 char *outfile_name = NULL;
130 if (strncmp (p, "aot", 3))
135 for (; *p; p = opt) {
141 if ((opt = match_option (p, "help", NULL)) != p) {
145 if ((opt = match_option (p, "verbose", NULL)) != p) {
149 if ((opt = match_option (p, "output", &val)) != p) {
153 fprintf (stderr, "mono-profiler-aot: Unknown option: '%s'.\n", p);
158 fprintf (stderr, "mono-profiler-aot: The 'output' argument is required.\n");
162 prof = g_new0 (MonoProfiler, 1);
163 prof->images = g_hash_table_new (NULL, NULL);
164 prof->classes = g_hash_table_new (NULL, NULL);
165 prof->methods = g_ptr_array_new ();
166 prof->outfile_name = outfile_name;
168 mono_os_mutex_init (&mutex);
170 MonoProfilerHandle handle = mono_profiler_create (prof);
171 mono_profiler_set_runtime_shutdown_end_callback (handle, prof_shutdown);
172 mono_profiler_set_jit_done_callback (handle, prof_jit_leave);
176 emit_byte (MonoProfiler *prof, guint8 value)
178 fwrite (&value, 1, 1, prof->outfile);
182 emit_int32 (MonoProfiler *prof, int value)
185 fwrite (&value, 4, 1, prof->outfile);
189 emit_string (MonoProfiler *prof, const char *str)
191 int len = strlen (str);
193 emit_int32 (prof, len);
194 fwrite (str, len, 1, prof->outfile);
198 emit_record (MonoProfiler *prof, AotProfRecordType type, int id)
200 emit_byte (prof, type);
201 emit_int32 (prof, id);
205 add_image (MonoProfiler *prof, MonoImage *image)
207 int id = GPOINTER_TO_INT (g_hash_table_lookup (prof->images, image));
212 emit_record (prof, AOTPROF_RECORD_IMAGE, id);
213 emit_string (prof, image->assembly->aname.name);
214 emit_string (prof, image->guid);
215 g_hash_table_insert (prof->images, image, GINT_TO_POINTER (id + 1));
220 add_class (MonoProfiler *prof, MonoClass *klass);
223 add_type (MonoProfiler *prof, MonoType *type)
225 switch (type->type) {
227 case MONO_TYPE_SZARRAY: {
228 int eid = add_type (prof, &type->data.klass->byval_arg);
231 int id = prof->id ++;
232 emit_record (prof, AOTPROF_RECORD_TYPE, id);
233 emit_byte (prof, MONO_TYPE_SZARRAY);
234 emit_int32 (prof, id);
238 case MONO_TYPE_BOOLEAN:
252 case MONO_TYPE_OBJECT:
253 case MONO_TYPE_STRING:
254 case MONO_TYPE_CLASS:
255 case MONO_TYPE_VALUETYPE:
256 case MONO_TYPE_GENERICINST:
257 return add_class (prof, mono_class_from_mono_type (type));
264 add_ginst (MonoProfiler *prof, MonoGenericInst *inst)
270 ids = g_malloc0 (inst->type_argc * sizeof (int));
271 for (i = 0; i < inst->type_argc; ++i) {
272 MonoType *t = inst->type_argv [i];
273 ids [i] = add_type (prof, t);
280 emit_record (prof, AOTPROF_RECORD_GINST, id);
281 emit_int32 (prof, inst->type_argc);
282 for (i = 0; i < inst->type_argc; ++i)
283 emit_int32 (prof, ids [i]);
290 add_class (MonoProfiler *prof, MonoClass *klass)
292 int id, inst_id = -1, image_id;
295 id = GPOINTER_TO_INT (g_hash_table_lookup (prof->classes, klass));
299 image_id = add_image (prof, klass->image);
301 if (mono_class_is_ginst (klass)) {
302 MonoGenericContext *ctx = mono_class_get_context (klass);
303 inst_id = add_ginst (prof, ctx->class_inst);
308 if (klass->nested_in)
309 name = g_strdup_printf ("%s.%s/%s", klass->nested_in->name_space, klass->nested_in->name, klass->name);
311 name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
314 emit_record (prof, AOTPROF_RECORD_TYPE, id);
315 emit_byte (prof, MONO_TYPE_CLASS);
316 emit_int32 (prof, image_id);
317 emit_int32 (prof, inst_id);
318 emit_string (prof, name);
320 g_hash_table_insert (prof->classes, klass, GINT_TO_POINTER (id + 1));
325 add_method (MonoProfiler *prof, MonoMethod *m)
328 MonoMethodSignature *sig;
331 sig = mono_method_signature_checked (m, &error);
332 g_assert (mono_error_ok (&error));
334 int class_id = add_class (prof, m->klass);
339 if (m->is_inflated) {
340 MonoGenericContext *ctx = mono_method_get_context (m);
341 if (ctx->method_inst)
342 inst_id = add_ginst (prof, ctx->method_inst);
344 int id = prof->id ++;
345 emit_record (prof, AOTPROF_RECORD_METHOD, id);
346 emit_int32 (prof, class_id);
347 emit_int32 (prof, inst_id);
348 emit_int32 (prof, sig->param_count);
349 emit_string (prof, m->name);
350 s = mono_signature_full_name (sig);
351 emit_string (prof, s);
354 printf ("%s %d\n", mono_method_full_name (m, 1), id);
357 /* called at the end of the program */
359 prof_shutdown (MonoProfiler *prof)
365 printf ("Creating output file: %s\n", prof->outfile_name);
367 if (prof->outfile_name [0] == '#') {
368 int fd = strtol (prof->outfile_name + 1, NULL, 10);
369 outfile = fdopen (fd, "a");
371 outfile = fopen (prof->outfile_name, "w+");
374 fprintf (stderr, "Unable to create output file '%s': %s.\n", prof->outfile_name, strerror (errno));
377 prof->outfile = outfile;
379 gint32 version = (AOT_PROFILER_MAJOR_VERSION << 16) | AOT_PROFILER_MINOR_VERSION;
380 sprintf (magic, AOT_PROFILER_MAGIC);
381 fwrite (magic, strlen (magic), 1, outfile);
382 emit_int32 (prof, version);
384 GHashTable *all_methods = g_hash_table_new (NULL, NULL);
385 for (mindex = 0; mindex < prof->methods->len; ++mindex) {
386 MonoMethod *m = (MonoMethod*)g_ptr_array_index (prof->methods, mindex);
388 if (!mono_method_get_token (m))
391 if (g_hash_table_lookup (all_methods, m))
393 g_hash_table_insert (all_methods, m, m);
395 add_method (prof, m);
397 emit_record (prof, AOTPROF_RECORD_NONE, 0);
401 g_hash_table_destroy (all_methods);
402 g_hash_table_destroy (prof->classes);
403 g_hash_table_destroy (prof->images);
404 g_ptr_array_free (prof->methods, TRUE);
405 g_free (prof->outfile_name);