[System] Tweak socket test
[mono-project.git] / mono / profiler / mono-profiler-aot.c
blob59f8aeea2a0a838e89d3cf8ca5422d65db89c60c
1 /*
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.
15 #include <config.h>
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>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <glib.h>
30 #include <sys/stat.h>
32 #ifdef HOST_WIN32
33 #include <direct.h>
34 #endif
36 struct _MonoProfiler {
37 GHashTable *classes;
38 GHashTable *images;
39 GPtrArray *methods;
40 FILE *outfile;
41 int id;
42 char *outfile_name;
45 static mono_mutex_t mutex;
46 static gboolean verbose;
48 static void
49 prof_jit_enter (MonoProfiler *prof, MonoMethod *method)
53 static void
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)
59 return;
61 mono_os_mutex_lock (&mutex);
62 g_ptr_array_add (prof->methods, method);
63 mono_os_mutex_unlock (&mutex);
66 static void
67 prof_shutdown (MonoProfiler *prof);
69 static void
70 usage (int do_exit)
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");
78 if (do_exit)
79 exit (1);
82 static const char*
83 match_option (const char* p, const char *opt, char **rval)
85 int len = strlen (opt);
86 if (strncmp (p, opt, len) == 0) {
87 if (rval) {
88 if (p [len] == '=' && p [len + 1]) {
89 const char *opt = p + len + 1;
90 const char *end = strchr (opt, ',');
91 char *val;
92 int l;
93 if (end == NULL) {
94 l = strlen (opt);
95 } else {
96 l = end - opt;
98 val = (char *) g_malloc (l + 1);
99 memcpy (val, opt, l);
100 val [l] = 0;
101 *rval = val;
102 return opt + l;
104 if (p [len] == 0 || p [len] == ',') {
105 *rval = NULL;
106 return p + len + (p [len] == ',');
108 usage (1);
109 } else {
110 if (p [len] == 0)
111 return p + len;
112 if (p [len] == ',')
113 return p + len + 1;
116 return p;
119 void
120 mono_profiler_startup (const char *desc);
122 /* the entry point */
123 void
124 mono_profiler_startup (const char *desc)
126 MonoProfiler *prof;
127 const char *p;
128 const char *opt;
129 char *outfile_name;
131 p = desc;
132 if (strncmp (p, "aot", 3))
133 usage (1);
134 p += 3;
135 if (*p == ':')
136 p++;
137 for (; *p; p = opt) {
138 char *val;
139 if (*p == ',') {
140 opt = p + 1;
141 continue;
143 if ((opt = match_option (p, "help", NULL)) != p) {
144 usage (0);
145 continue;
147 if ((opt = match_option (p, "verbose", NULL)) != p) {
148 verbose = TRUE;
149 continue;
151 if ((opt = match_option (p, "output", &val)) != p) {
152 outfile_name = val;
153 continue;
155 fprintf (stderr, "mono-profiler-aot: Unknown option: '%s'.\n", p);
156 exit (1);
159 if (!outfile_name) {
160 fprintf (stderr, "mono-profiler-aot: The 'output' argument is required.\n");
161 exit (1);
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);
179 static void
180 emit_byte (MonoProfiler *prof, guint8 value)
182 fwrite (&value, 1, 1, prof->outfile);
185 static void
186 emit_int32 (MonoProfiler *prof, int value)
188 // FIXME: Endianness
189 fwrite (&value, 4, 1, prof->outfile);
192 static void
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);
201 static void
202 emit_record (MonoProfiler *prof, AotProfRecordType type, int id)
204 emit_byte (prof, type);
205 emit_int32 (prof, id);
208 static int
209 add_image (MonoProfiler *prof, MonoImage *image)
211 int id = GPOINTER_TO_INT (g_hash_table_lookup (prof->images, image));
212 if (id)
213 return id - 1;
215 id = prof->id ++;
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));
220 return id;
223 static int
224 add_class (MonoProfiler *prof, MonoClass *klass);
226 static int
227 add_type (MonoProfiler *prof, MonoType *type)
229 switch (type->type) {
230 #if 0
231 case MONO_TYPE_SZARRAY: {
232 int eid = add_type (prof, &type->data.klass->byval_arg);
233 if (eid == -1)
234 return -1;
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);
239 return id;
241 #endif
242 case MONO_TYPE_BOOLEAN:
243 case MONO_TYPE_CHAR:
244 case MONO_TYPE_I1:
245 case MONO_TYPE_U1:
246 case MONO_TYPE_I2:
247 case MONO_TYPE_U2:
248 case MONO_TYPE_I4:
249 case MONO_TYPE_U4:
250 case MONO_TYPE_I8:
251 case MONO_TYPE_U8:
252 case MONO_TYPE_R4:
253 case MONO_TYPE_R8:
254 case MONO_TYPE_I:
255 case MONO_TYPE_U:
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));
262 default:
263 return -1;
267 static int
268 add_ginst (MonoProfiler *prof, MonoGenericInst *inst)
270 int i, id;
271 int *ids;
273 // FIXME: Cache
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);
278 if (ids [i] == -1) {
279 g_free (ids);
280 return -1;
283 id = prof->id ++;
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]);
288 g_free (ids);
290 return id;
293 static int
294 add_class (MonoProfiler *prof, MonoClass *klass)
296 int id, inst_id = -1, image_id;
297 char *name;
299 id = GPOINTER_TO_INT (g_hash_table_lookup (prof->classes, klass));
300 if (id)
301 return id - 1;
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);
308 if (inst_id == -1)
309 return -1;
312 if (klass->nested_in)
313 name = g_strdup_printf ("%s.%s/%s", klass->nested_in->name_space, klass->nested_in->name, klass->name);
314 else
315 name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
317 id = prof->id ++;
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);
323 g_free (name);
324 g_hash_table_insert (prof->classes, klass, GINT_TO_POINTER (id + 1));
325 return id;
328 static void
329 add_method (MonoProfiler *prof, MonoMethod *m)
331 MonoError error;
332 MonoMethodSignature *sig;
333 char *s;
335 sig = mono_method_signature_checked (m, &error);
336 g_assert (mono_error_ok (&error));
338 int class_id = add_class (prof, m->klass);
339 if (class_id == -1)
340 return;
341 int inst_id = -1;
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);
356 g_free (s);
357 if (verbose)
358 printf ("%s %d\n", mono_method_full_name (m, 1), id);
361 /* called at the end of the program */
362 static void
363 prof_shutdown (MonoProfiler *prof)
365 FILE *outfile;
366 int mindex;
367 char magic [32];
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");
374 } else {
375 outfile = fopen (prof->outfile_name, "w+");
377 if (!outfile) {
378 fprintf (stderr, "Unable to create output file '%s': %s.\n", prof->outfile_name, strerror (errno));
379 return;
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))
393 continue;
395 if (g_hash_table_lookup (all_methods, m))
396 continue;
397 g_hash_table_insert (all_methods, m, m);
399 add_method (prof, m);
401 emit_record (prof, AOTPROF_RECORD_NONE, 0);
403 fclose (outfile);
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);