2 * mono-profiler-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.
17 #include "mono-profiler-aot.h"
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_enter (MonoProfiler
*prof
, MonoMethod
*method
)
54 prof_jit_leave (MonoProfiler
*prof
, MonoMethod
*method
, int result
)
56 MonoImage
*image
= mono_class_get_image (mono_method_get_class (method
));
58 if (!image
->assembly
|| method
->wrapper_type
)
61 mono_os_mutex_lock (&mutex
);
62 g_ptr_array_add (prof
->methods
, method
);
63 mono_os_mutex_unlock (&mutex
);
67 prof_shutdown (MonoProfiler
*prof
);
72 printf ("AOT profiler.\n");
73 printf ("Usage: mono --profile=aot[:OPTION1[,OPTION2...]] program.exe\n");
74 printf ("Options:\n");
75 printf ("\thelp show this usage info\n");
76 printf ("\toutput=FILENAME write the data to file FILENAME (required)\n");
77 printf ("\tverbose print diagnostic info\n");
83 match_option (const char* p
, const char *opt
, char **rval
)
85 int len
= strlen (opt
);
86 if (strncmp (p
, opt
, len
) == 0) {
88 if (p
[len
] == '=' && p
[len
+ 1]) {
89 const char *opt
= p
+ len
+ 1;
90 const char *end
= strchr (opt
, ',');
98 val
= (char *) g_malloc (l
+ 1);
104 if (p
[len
] == 0 || p
[len
] == ',') {
106 return p
+ len
+ (p
[len
] == ',');
120 mono_profiler_startup (const char *desc
);
122 /* the entry point */
124 mono_profiler_startup (const char *desc
)
132 if (strncmp (p
, "aot", 3))
137 for (; *p
; p
= opt
) {
143 if ((opt
= match_option (p
, "help", NULL
)) != p
) {
147 if ((opt
= match_option (p
, "verbose", NULL
)) != p
) {
151 if ((opt
= match_option (p
, "output", &val
)) != p
) {
155 fprintf (stderr
, "mono-profiler-aot: Unknown option: '%s'.\n", p
);
160 fprintf (stderr
, "mono-profiler-aot: The 'output' argument is required.\n");
164 prof
= g_new0 (MonoProfiler
, 1);
165 prof
->images
= g_hash_table_new (NULL
, NULL
);
166 prof
->classes
= g_hash_table_new (NULL
, NULL
);
167 prof
->methods
= g_ptr_array_new ();
168 prof
->outfile_name
= outfile_name
;
170 mono_os_mutex_init (&mutex
);
172 mono_profiler_install (prof
, prof_shutdown
);
174 mono_profiler_install_jit_compile (prof_jit_enter
, prof_jit_leave
);
176 mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION
);
180 emit_byte (MonoProfiler
*prof
, guint8 value
)
182 fwrite (&value
, 1, 1, prof
->outfile
);
186 emit_int32 (MonoProfiler
*prof
, int value
)
189 fwrite (&value
, 4, 1, prof
->outfile
);
193 emit_string (MonoProfiler
*prof
, const char *str
)
195 int len
= strlen (str
);
197 emit_int32 (prof
, len
);
198 fwrite (str
, len
, 1, prof
->outfile
);
202 emit_record (MonoProfiler
*prof
, AotProfRecordType type
, int id
)
204 emit_byte (prof
, type
);
205 emit_int32 (prof
, id
);
209 add_image (MonoProfiler
*prof
, MonoImage
*image
)
211 int id
= GPOINTER_TO_INT (g_hash_table_lookup (prof
->images
, image
));
216 emit_record (prof
, AOTPROF_RECORD_IMAGE
, id
);
217 emit_string (prof
, image
->assembly
->aname
.name
);
218 emit_string (prof
, image
->guid
);
219 g_hash_table_insert (prof
->images
, image
, GINT_TO_POINTER (id
+ 1));
224 add_class (MonoProfiler
*prof
, MonoClass
*klass
);
227 add_type (MonoProfiler
*prof
, MonoType
*type
)
229 switch (type
->type
) {
231 case MONO_TYPE_SZARRAY
: {
232 int eid
= add_type (prof
, &type
->data
.klass
->byval_arg
);
235 int id
= prof
->id
++;
236 emit_record (prof
, AOTPROF_RECORD_TYPE
, id
);
237 emit_byte (prof
, MONO_TYPE_SZARRAY
);
238 emit_int32 (prof
, id
);
242 case MONO_TYPE_BOOLEAN
:
256 case MONO_TYPE_OBJECT
:
257 case MONO_TYPE_STRING
:
258 case MONO_TYPE_CLASS
:
259 case MONO_TYPE_VALUETYPE
:
260 case MONO_TYPE_GENERICINST
:
261 return add_class (prof
, mono_class_from_mono_type (type
));
268 add_ginst (MonoProfiler
*prof
, MonoGenericInst
*inst
)
274 ids
= g_malloc0 (inst
->type_argc
* sizeof (int));
275 for (i
= 0; i
< inst
->type_argc
; ++i
) {
276 MonoType
*t
= inst
->type_argv
[i
];
277 ids
[i
] = add_type (prof
, t
);
284 emit_record (prof
, AOTPROF_RECORD_GINST
, id
);
285 emit_int32 (prof
, inst
->type_argc
);
286 for (i
= 0; i
< inst
->type_argc
; ++i
)
287 emit_int32 (prof
, ids
[i
]);
294 add_class (MonoProfiler
*prof
, MonoClass
*klass
)
296 int id
, inst_id
= -1, image_id
;
299 id
= GPOINTER_TO_INT (g_hash_table_lookup (prof
->classes
, klass
));
303 image_id
= add_image (prof
, klass
->image
);
305 if (mono_class_is_ginst (klass
)) {
306 MonoGenericContext
*ctx
= mono_class_get_context (klass
);
307 inst_id
= add_ginst (prof
, ctx
->class_inst
);
312 if (klass
->nested_in
)
313 name
= g_strdup_printf ("%s.%s/%s", klass
->nested_in
->name_space
, klass
->nested_in
->name
, klass
->name
);
315 name
= g_strdup_printf ("%s.%s", klass
->name_space
, klass
->name
);
318 emit_record (prof
, AOTPROF_RECORD_TYPE
, id
);
319 emit_byte (prof
, MONO_TYPE_CLASS
);
320 emit_int32 (prof
, image_id
);
321 emit_int32 (prof
, inst_id
);
322 emit_string (prof
, name
);
324 g_hash_table_insert (prof
->classes
, klass
, GINT_TO_POINTER (id
+ 1));
329 add_method (MonoProfiler
*prof
, MonoMethod
*m
)
332 MonoMethodSignature
*sig
;
335 sig
= mono_method_signature_checked (m
, &error
);
336 g_assert (mono_error_ok (&error
));
338 int class_id
= add_class (prof
, m
->klass
);
343 if (m
->is_inflated
) {
344 MonoGenericContext
*ctx
= mono_method_get_context (m
);
345 if (ctx
->method_inst
)
346 inst_id
= add_ginst (prof
, ctx
->method_inst
);
348 int id
= prof
->id
++;
349 emit_record (prof
, AOTPROF_RECORD_METHOD
, id
);
350 emit_int32 (prof
, class_id
);
351 emit_int32 (prof
, inst_id
);
352 emit_int32 (prof
, sig
->param_count
);
353 emit_string (prof
, m
->name
);
354 s
= mono_signature_full_name (sig
);
355 emit_string (prof
, s
);
358 printf ("%s %d\n", mono_method_full_name (m
, 1), id
);
361 /* called at the end of the program */
363 prof_shutdown (MonoProfiler
*prof
)
369 printf ("Creating output file: %s\n", prof
->outfile_name
);
371 if (prof
->outfile_name
[0] == '#') {
372 int fd
= strtol (prof
->outfile_name
+ 1, NULL
, 10);
373 outfile
= fdopen (fd
, "a");
375 outfile
= fopen (prof
->outfile_name
, "w+");
378 fprintf (stderr
, "Unable to create output file '%s': %s.\n", prof
->outfile_name
, strerror (errno
));
381 prof
->outfile
= outfile
;
383 gint32 version
= (AOT_PROFILER_MAJOR_VERSION
<< 16) | AOT_PROFILER_MINOR_VERSION
;
384 sprintf (magic
, AOT_PROFILER_MAGIC
);
385 fwrite (magic
, strlen (magic
), 1, outfile
);
386 emit_int32 (prof
, version
);
388 GHashTable
*all_methods
= g_hash_table_new (NULL
, NULL
);
389 for (mindex
= 0; mindex
< prof
->methods
->len
; ++mindex
) {
390 MonoMethod
*m
= (MonoMethod
*)g_ptr_array_index (prof
->methods
, mindex
);
392 if (!mono_method_get_token (m
))
395 if (g_hash_table_lookup (all_methods
, m
))
397 g_hash_table_insert (all_methods
, m
, m
);
399 add_method (prof
, m
);
401 emit_record (prof
, AOTPROF_RECORD_NONE
, 0);
405 g_hash_table_destroy (all_methods
);
406 g_hash_table_destroy (prof
->classes
);
407 g_hash_table_destroy (prof
->images
);
408 g_ptr_array_free (prof
->methods
, TRUE
);
409 g_free (prof
->outfile_name
);