Skip to content

Commit 16cf089

Browse files
author
Alex Rønne Petersen
committed
[profiler] Clean up the AOT profiler a bit.
* Use the same option parsing logic as the other profilers. * Support the same output file syntax as the other profilers. * Use output.aotprofile as the default output file name. * Open the output file on startup rather than shutdown. * Use runtime logging functions instead of printf/fprintf. * Don't print anything unless the verbose option is given. * Fix an endianness issue with writing ints to the output file. * Move all profiler state into MonoProfiler structure and store it statically. * Remove outdated comments and includes.
1 parent 0f985ed commit 16cf089

File tree

4 files changed

+135
-122
lines changed

4 files changed

+135
-122
lines changed

mono/profiler/aot.c

Lines changed: 132 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
*
44
*
55
* 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.
126
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
137
*/
148

@@ -22,16 +16,12 @@
2216
#include <mono/metadata/debug-helpers.h>
2317
#include <mono/metadata/assembly.h>
2418
#include <mono/metadata/class-internals.h>
19+
#include <mono/utils/mono-logger-internals.h>
2520
#include <mono/utils/mono-os-mutex.h>
2621
#include <string.h>
2722
#include <errno.h>
2823
#include <stdlib.h>
2924
#include <glib.h>
30-
#include <sys/stat.h>
31-
32-
#ifdef HOST_WIN32
33-
#include <direct.h>
34-
#endif
3525

3626
struct _MonoProfiler {
3727
GHashTable *classes;
@@ -40,75 +30,130 @@ struct _MonoProfiler {
4030
FILE *outfile;
4131
int id;
4232
char *outfile_name;
33+
mono_mutex_t mutex;
34+
gboolean verbose;
4335
};
4436

45-
static mono_mutex_t mutex;
46-
static gboolean verbose;
37+
static MonoProfiler aot_profiler;
4738

4839
static void
49-
prof_jit_leave (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
40+
prof_jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
5041
{
5142
MonoImage *image = mono_class_get_image (mono_method_get_class (method));
5243

5344
if (!image->assembly || method->wrapper_type)
5445
return;
5546

56-
mono_os_mutex_lock (&mutex);
47+
mono_os_mutex_lock (&prof->mutex);
5748
g_ptr_array_add (prof->methods, method);
58-
mono_os_mutex_unlock (&mutex);
49+
mono_os_mutex_unlock (&prof->mutex);
5950
}
6051

6152
static void
6253
prof_shutdown (MonoProfiler *prof);
6354

6455
static void
65-
usage (int do_exit)
56+
usage (void)
6657
{
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+
}
75102
}
76103

77-
static const char*
78-
match_option (const char* p, const char *opt, char **rval)
104+
static void
105+
parse_args (const char *desc)
79106
{
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;
92121
}
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++;
98131
}
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;
102143
}
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;
109148
}
110149
}
111-
return p;
150+
151+
if (buffer_pos != 0) {
152+
buffer [buffer_pos] = 0;
153+
parse_arg (buffer);
154+
}
155+
156+
g_free (buffer);
112157
}
113158

114159
void
@@ -121,68 +166,50 @@ mono_profiler_init_aot (const char *desc);
121166
void
122167
mono_profiler_init_aot (const char *desc)
123168
{
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 ());
156175

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));
159185
exit (1);
160186
}
161187

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 ();
167191

168-
mono_os_mutex_init (&mutex);
192+
mono_os_mutex_init (&aot_profiler.mutex);
169193

170-
MonoProfilerHandle handle = mono_profiler_create (prof);
194+
MonoProfilerHandle handle = mono_profiler_create (&aot_profiler);
171195
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);
173197
}
174198

175199
static void
176200
emit_byte (MonoProfiler *prof, guint8 value)
177201
{
178-
fwrite (&value, 1, 1, prof->outfile);
202+
fwrite (&value, sizeof (guint8), 1, prof->outfile);
179203
}
180204

181205
static void
182-
emit_int32 (MonoProfiler *prof, int value)
206+
emit_int32 (MonoProfiler *prof, gint32 value)
183207
{
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+
}
186213
}
187214

188215
static void
@@ -350,35 +377,21 @@ add_method (MonoProfiler *prof, MonoMethod *m)
350377
s = mono_signature_full_name (sig);
351378
emit_string (prof, s);
352379
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);
355383
}
356384

357385
/* called at the end of the program */
358386
static void
359387
prof_shutdown (MonoProfiler *prof)
360388
{
361-
FILE *outfile;
362389
int mindex;
363390
char magic [32];
364391

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-
379392
gint32 version = (AOT_PROFILER_MAJOR_VERSION << 16) | AOT_PROFILER_MINOR_VERSION;
380393
sprintf (magic, AOT_PROFILER_MAGIC);
381-
fwrite (magic, strlen (magic), 1, outfile);
394+
fwrite (magic, strlen (magic), 1, prof->outfile);
382395
emit_int32 (prof, version);
383396

384397
GHashTable *all_methods = g_hash_table_new (NULL, NULL);
@@ -396,7 +409,7 @@ prof_shutdown (MonoProfiler *prof)
396409
}
397410
emit_record (prof, AOTPROF_RECORD_NONE, 0);
398411

399-
fclose (outfile);
412+
fclose (prof->outfile);
400413

401414
g_hash_table_destroy (all_methods);
402415
g_hash_table_destroy (prof->classes);

mono/profiler/aot.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/*
77
* File format:
88
* - magic (AOT_PROFILER_MAGIC)
9-
* - int: major/minor version, e.g. 0x00010001 (AOT_PROFILER_MAJOR_VERSION, AOT_PROFILER_MINOR_VERSION)
9+
* - int: major/minor version, e.g. 0x00010000 (AOT_PROFILER_MAJOR_VERSION, AOT_PROFILER_MINOR_VERSION)
1010
* - sequence of records terminated by an AOTPROF_RECORD_NONE record
1111
*
1212
* Record format:

mono/profiler/coverage.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ mono_profiler_init_coverage (const char *desc)
917917
coverage_profiler.file = fopen (coverage_config.output_filename, "w");
918918

919919
if (!coverage_profiler.file) {
920-
mono_profiler_printf_err ("Could not create coverage profiler output file '%s'.", coverage_config.output_filename);
920+
mono_profiler_printf_err ("Could not create coverage profiler output file '%s': %s", coverage_config.output_filename, g_strerror (errno));
921921
exit (1);
922922
}
923923

mono/profiler/log.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4602,7 +4602,7 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters)
46024602
log_profiler.file = fopen (nf, "wb");
46034603

46044604
if (!log_profiler.file) {
4605-
mono_profiler_printf_err ("Could not create log profiler output file '%s'.", nf);
4605+
mono_profiler_printf_err ("Could not create log profiler output file '%s': %s", nf, g_strerror (errno));
46064606
exit (1);
46074607
}
46084608

0 commit comments

Comments
 (0)