3
3
*
4
4
*
5
5
* Copyright 2008-2009 Novell, Inc (http://www.novell.com)
6
- *
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
6
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
13
7
*/
14
8
22
16
#include <mono/metadata/debug-helpers.h>
23
17
#include <mono/metadata/assembly.h>
24
18
#include <mono/metadata/class-internals.h>
19
+ #include <mono/utils/mono-logger-internals.h>
25
20
#include <mono/utils/mono-os-mutex.h>
26
21
#include <string.h>
27
22
#include <errno.h>
28
23
#include <stdlib.h>
29
24
#include <glib.h>
30
- #include <sys/stat.h>
31
-
32
- #ifdef HOST_WIN32
33
- #include <direct.h>
34
- #endif
35
25
36
26
struct _MonoProfiler {
37
27
GHashTable * classes ;
@@ -40,75 +30,130 @@ struct _MonoProfiler {
40
30
FILE * outfile ;
41
31
int id ;
42
32
char * outfile_name ;
33
+ mono_mutex_t mutex ;
34
+ gboolean verbose ;
43
35
};
44
36
45
- static mono_mutex_t mutex ;
46
- static gboolean verbose ;
37
+ static MonoProfiler aot_profiler ;
47
38
48
39
static void
49
- prof_jit_leave (MonoProfiler * prof , MonoMethod * method , MonoJitInfo * jinfo )
40
+ prof_jit_done (MonoProfiler * prof , MonoMethod * method , MonoJitInfo * jinfo )
50
41
{
51
42
MonoImage * image = mono_class_get_image (mono_method_get_class (method ));
52
43
53
44
if (!image -> assembly || method -> wrapper_type )
54
45
return ;
55
46
56
- mono_os_mutex_lock (& mutex );
47
+ mono_os_mutex_lock (& prof -> mutex );
57
48
g_ptr_array_add (prof -> methods , method );
58
- mono_os_mutex_unlock (& mutex );
49
+ mono_os_mutex_unlock (& prof -> mutex );
59
50
}
60
51
61
52
static void
62
53
prof_shutdown (MonoProfiler * prof );
63
54
64
55
static void
65
- usage (int do_exit )
56
+ usage (void )
66
57
{
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" );
73
- if (do_exit )
74
- exit (1 );
58
+ mono_profiler_printf ("AOT profiler.\n" );
59
+ mono_profiler_printf ("Usage: mono --profile=aot[:OPTION1[,OPTION2...]] program.exe\n" );
60
+ mono_profiler_printf ("Options:\n" );
61
+ mono_profiler_printf ("\thelp show this usage info\n" );
62
+ mono_profiler_printf ("\toutput=FILENAME write the data to file FILENAME\n" );
63
+ mono_profiler_printf ("\tverbose print diagnostic info\n" );
64
+
65
+ exit (0 );
66
+ }
67
+
68
+ static gboolean
69
+ match_option (const char * arg , const char * opt_name , const char * * rval )
70
+ {
71
+ if (rval ) {
72
+ const char * end = strchr (arg , '=' );
73
+
74
+ * rval = NULL ;
75
+ if (!end )
76
+ return !strcmp (arg , opt_name );
77
+
78
+ if (strncmp (arg , opt_name , strlen (opt_name )) || (end - arg ) > strlen (opt_name ) + 1 )
79
+ return FALSE;
80
+ * rval = end + 1 ;
81
+ return TRUE;
82
+ } else {
83
+ //FIXME how should we handle passing a value to an arg that doesn't expect it?
84
+ return !strcmp (arg , opt_name );
85
+ }
86
+ }
87
+
88
+ static void
89
+ parse_arg (const char * arg )
90
+ {
91
+ const char * val ;
92
+
93
+ if (match_option (arg , "help" , NULL )) {
94
+ usage ();
95
+ } else if (match_option (arg , "output" , & val )) {
96
+ aot_profiler .outfile_name = g_strdup (val );
97
+ } else if (match_option (arg , "verbose" , NULL )) {
98
+ aot_profiler .verbose = TRUE;
99
+ } else {
100
+ mono_profiler_printf_err ("Could not parse argument: %s" , arg );
101
+ }
75
102
}
76
103
77
- static const char *
78
- match_option (const char * p , const char * opt , char * * rval )
104
+ static void
105
+ parse_args (const char * desc )
79
106
{
80
- int len = strlen (opt );
81
- if (strncmp (p , opt , len ) == 0 ) {
82
- if (rval ) {
83
- if (p [len ] == '=' && p [len + 1 ]) {
84
- const char * opt = p + len + 1 ;
85
- const char * end = strchr (opt , ',' );
86
- char * val ;
87
- int l ;
88
- if (end == NULL ) {
89
- l = strlen (opt );
90
- } else {
91
- l = end - opt ;
107
+ const char * p ;
108
+ gboolean in_quotes = FALSE;
109
+ char quote_char = '\0' ;
110
+ char * buffer = malloc (strlen (desc ));
111
+ int buffer_pos = 0 ;
112
+
113
+ for (p = desc ; * p ; p ++ ){
114
+ switch (* p ){
115
+ case ',' :
116
+ if (!in_quotes ) {
117
+ if (buffer_pos != 0 ){
118
+ buffer [buffer_pos ] = 0 ;
119
+ parse_arg (buffer );
120
+ buffer_pos = 0 ;
92
121
}
93
- val = (char * ) g_malloc (l + 1 );
94
- memcpy (val , opt , l );
95
- val [l ] = 0 ;
96
- * rval = val ;
97
- return opt + l ;
122
+ } else {
123
+ buffer [buffer_pos ++ ] = * p ;
124
+ }
125
+ break ;
126
+
127
+ case '\\' :
128
+ if (p [1 ]) {
129
+ buffer [buffer_pos ++ ] = p [1 ];
130
+ p ++ ;
98
131
}
99
- if (p [len ] == 0 || p [len ] == ',' ) {
100
- * rval = NULL ;
101
- return p + len + (p [len ] == ',' );
132
+ break ;
133
+ case '\'' :
134
+ case '"' :
135
+ if (in_quotes ) {
136
+ if (quote_char == * p )
137
+ in_quotes = FALSE;
138
+ else
139
+ buffer [buffer_pos ++ ] = * p ;
140
+ } else {
141
+ in_quotes = TRUE;
142
+ quote_char = * p ;
102
143
}
103
- usage (1 );
104
- } else {
105
- if (p [len ] == 0 )
106
- return p + len ;
107
- if (p [len ] == ',' )
108
- return p + len + 1 ;
144
+ break ;
145
+ default :
146
+ buffer [buffer_pos ++ ] = * p ;
147
+ break ;
109
148
}
110
149
}
111
- return p ;
150
+
151
+ if (buffer_pos != 0 ) {
152
+ buffer [buffer_pos ] = 0 ;
153
+ parse_arg (buffer );
154
+ }
155
+
156
+ g_free (buffer );
112
157
}
113
158
114
159
void
@@ -121,68 +166,50 @@ mono_profiler_init_aot (const char *desc);
121
166
void
122
167
mono_profiler_init_aot (const char * desc )
123
168
{
124
- MonoProfiler * prof ;
125
- const char * p ;
126
- const char * opt ;
127
- char * outfile_name = NULL ;
128
-
129
- p = desc ;
130
- if (strncmp (p , "aot" , 3 ))
131
- usage (1 );
132
- p += 3 ;
133
- if (* p == ':' )
134
- p ++ ;
135
- for (; * p ; p = opt ) {
136
- char * val ;
137
- if (* p == ',' ) {
138
- opt = p + 1 ;
139
- continue ;
140
- }
141
- if ((opt = match_option (p , "help" , NULL )) != p ) {
142
- usage (0 );
143
- continue ;
144
- }
145
- if ((opt = match_option (p , "verbose" , NULL )) != p ) {
146
- verbose = TRUE;
147
- continue ;
148
- }
149
- if ((opt = match_option (p , "output" , & val )) != p ) {
150
- outfile_name = val ;
151
- continue ;
152
- }
153
- fprintf (stderr , "mono-profiler-aot: Unknown option: '%s'.\n" , p );
154
- exit (1 );
155
- }
169
+ parse_args (desc [strlen ("aot" )] == ':' ? desc + strlen ("aot" ) + 1 : "" );
170
+
171
+ if (!aot_profiler .outfile_name )
172
+ aot_profiler .outfile_name = g_strdup ("output.aotprofile" );
173
+ else if (* aot_profiler .outfile_name == '+' )
174
+ aot_profiler .outfile_name = g_strdup_printf ("%s.%d" , aot_profiler .outfile_name + 1 , getpid ());
156
175
157
- if (!outfile_name ) {
158
- fprintf (stderr , "mono-profiler-aot: The 'output' argument is required.\n" );
176
+ if (* aot_profiler .outfile_name == '|' )
177
+ aot_profiler .outfile = popen (aot_profiler .outfile_name + 1 , "w" );
178
+ else if (* aot_profiler .outfile_name == '#' )
179
+ aot_profiler .outfile = fdopen (strtol (aot_profiler .outfile_name + 1 , NULL , 10 ), "a" );
180
+ else
181
+ aot_profiler .outfile = fopen (aot_profiler .outfile_name , "w" );
182
+
183
+ if (!aot_profiler .outfile ) {
184
+ mono_profiler_printf_err ("Could not create AOT profiler output file '%s': %s" , aot_profiler .outfile_name , g_strerror (errno ));
159
185
exit (1 );
160
186
}
161
187
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 ;
188
+ aot_profiler .images = g_hash_table_new (NULL , NULL );
189
+ aot_profiler .classes = g_hash_table_new (NULL , NULL );
190
+ aot_profiler .methods = g_ptr_array_new ();
167
191
168
- mono_os_mutex_init (& mutex );
192
+ mono_os_mutex_init (& aot_profiler . mutex );
169
193
170
- MonoProfilerHandle handle = mono_profiler_create (prof );
194
+ MonoProfilerHandle handle = mono_profiler_create (& aot_profiler );
171
195
mono_profiler_set_runtime_shutdown_end_callback (handle , prof_shutdown );
172
- mono_profiler_set_jit_done_callback (handle , prof_jit_leave );
196
+ mono_profiler_set_jit_done_callback (handle , prof_jit_done );
173
197
}
174
198
175
199
static void
176
200
emit_byte (MonoProfiler * prof , guint8 value )
177
201
{
178
- fwrite (& value , 1 , 1 , prof -> outfile );
202
+ fwrite (& value , sizeof ( guint8 ) , 1 , prof -> outfile );
179
203
}
180
204
181
205
static void
182
- emit_int32 (MonoProfiler * prof , int value )
206
+ emit_int32 (MonoProfiler * prof , gint32 value )
183
207
{
184
- // FIXME: Endianness
185
- fwrite (& value , 4 , 1 , prof -> outfile );
208
+ for (int i = 0 ; i < sizeof (gint32 ); ++ i ) {
209
+ guint8 b = value ;
210
+ fwrite (& b , sizeof (guint8 ), 1 , prof -> outfile );
211
+ value >>= 8 ;
212
+ }
186
213
}
187
214
188
215
static void
@@ -350,35 +377,21 @@ add_method (MonoProfiler *prof, MonoMethod *m)
350
377
s = mono_signature_full_name (sig );
351
378
emit_string (prof , s );
352
379
g_free (s );
353
- if (verbose )
354
- printf ("%s %d\n" , mono_method_full_name (m , 1 ), id );
380
+
381
+ if (prof -> verbose )
382
+ mono_profiler_printf ("%s %d\n" , mono_method_full_name (m , 1 ), id );
355
383
}
356
384
357
385
/* called at the end of the program */
358
386
static void
359
387
prof_shutdown (MonoProfiler * prof )
360
388
{
361
- FILE * outfile ;
362
389
int mindex ;
363
390
char magic [32 ];
364
391
365
- printf ("Creating output file: %s\n" , prof -> outfile_name );
366
-
367
- if (prof -> outfile_name [0 ] == '#' ) {
368
- int fd = strtol (prof -> outfile_name + 1 , NULL , 10 );
369
- outfile = fdopen (fd , "a" );
370
- } else {
371
- outfile = fopen (prof -> outfile_name , "w+" );
372
- }
373
- if (!outfile ) {
374
- fprintf (stderr , "Unable to create output file '%s': %s.\n" , prof -> outfile_name , strerror (errno ));
375
- return ;
376
- }
377
- prof -> outfile = outfile ;
378
-
379
392
gint32 version = (AOT_PROFILER_MAJOR_VERSION << 16 ) | AOT_PROFILER_MINOR_VERSION ;
380
393
sprintf (magic , AOT_PROFILER_MAGIC );
381
- fwrite (magic , strlen (magic ), 1 , outfile );
394
+ fwrite (magic , strlen (magic ), 1 , prof -> outfile );
382
395
emit_int32 (prof , version );
383
396
384
397
GHashTable * all_methods = g_hash_table_new (NULL , NULL );
@@ -396,7 +409,7 @@ prof_shutdown (MonoProfiler *prof)
396
409
}
397
410
emit_record (prof , AOTPROF_RECORD_NONE , 0 );
398
411
399
- fclose (outfile );
412
+ fclose (prof -> outfile );
400
413
401
414
g_hash_table_destroy (all_methods );
402
415
g_hash_table_destroy (prof -> classes );
0 commit comments