Improve a safety check when writing data into StatBuffer
[mono.git] / mono / profiler / mono-profiler-aot.c
1 /*
2  * mono-profiler-aot.c: Ahead of Time Compiler Profiler for Mono.
3  *
4  *
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  */
13
14 #include <config.h>
15 #include <mono/metadata/profiler.h>
16 #include <mono/metadata/tokentype.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/metadata/assembly.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <sys/stat.h>
25
26 #ifdef HOST_WIN32
27 #include <direct.h>
28 #endif
29
30 struct _MonoProfiler {
31         GHashTable *images;
32 };
33
34 typedef struct {
35         GList *methods;
36 } PerImageData;
37
38 typedef struct ForeachData {
39         MonoProfiler *prof;
40         FILE *outfile;
41         MonoImage *image;
42         MonoMethod *method;
43 } ForeachData;
44
45 static void
46 foreach_method (gpointer data, gpointer user_data)
47 {
48         ForeachData *udata = (ForeachData*)user_data;
49         MonoMethod *method = (MonoMethod*)data;
50         char *name;
51
52         if (!mono_method_get_token (method) || mono_class_get_image (mono_method_get_class (method)) != udata->image)
53                 return;
54
55         name = mono_method_full_name (method, TRUE);
56         fprintf (udata->outfile, "%s\n", name);
57         g_free (name);
58 }
59
60 static void
61 output_image (gpointer key, gpointer value, gpointer user_data)
62 {
63         MonoImage *image = (MonoImage*)key;
64         PerImageData *image_data = (PerImageData*)value;
65         MonoProfiler *prof = (MonoProfiler*)user_data;
66         char *tmp, *outfile_name;
67         FILE *outfile;
68         int i, err;
69         ForeachData data;
70
71         tmp = g_strdup_printf ("%s/.mono/aot-profile-data", g_get_home_dir ());
72
73         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
74 #ifdef HOST_WIN32
75                 err = mkdir (tmp);
76 #else
77                 err = mkdir (tmp, 0777);
78 #endif
79                 if (err) {
80                         fprintf (stderr, "mono-profiler-aot: Unable to create output directory '%s': %s\n", tmp, g_strerror (errno));
81                         exit (1);
82                 }
83         }
84
85         i = 0;
86         while (TRUE) {
87                 outfile_name = g_strdup_printf ("%s/%s-%d", tmp, mono_image_get_name (image), i);
88
89                 if (!g_file_test (outfile_name, G_FILE_TEST_IS_REGULAR))
90                         break;
91
92                 i ++;
93         }
94
95         printf ("Creating output file: %s\n", outfile_name);
96
97         outfile = fopen (outfile_name, "w+");
98         g_assert (outfile);
99
100         fprintf (outfile, "#VER:%d\n", 2);
101
102         data.prof = prof;
103         data.outfile = outfile;
104         data.image = image;
105
106         g_list_foreach (image_data->methods, foreach_method, &data);
107 }
108
109 /* called at the end of the program */
110 static void
111 prof_shutdown (MonoProfiler *prof)
112 {
113         g_hash_table_foreach (prof->images, output_image, prof);
114 }
115
116 static void
117 prof_jit_enter (MonoProfiler *prof, MonoMethod *method)
118 {
119 }
120
121 static void
122 prof_jit_leave (MonoProfiler *prof, MonoMethod *method, int result)
123 {
124         MonoImage *image = mono_class_get_image (mono_method_get_class (method));
125         PerImageData *data;
126
127         data = (PerImageData *)g_hash_table_lookup (prof->images, image);
128         if (!data) {
129                 data = g_new0 (PerImageData, 1);
130                 g_hash_table_insert (prof->images, image, data);
131         }
132
133         data->methods = g_list_append (data->methods, method);
134 }
135
136 void
137 mono_profiler_startup (const char *desc);
138
139 /* the entry point */
140 void
141 mono_profiler_startup (const char *desc)
142 {
143         MonoProfiler *prof;
144
145         prof = g_new0 (MonoProfiler, 1);
146         prof->images = g_hash_table_new (NULL, NULL);
147
148         mono_profiler_install (prof, prof_shutdown);
149         
150         mono_profiler_install_jit_compile (prof_jit_enter, prof_jit_leave);
151
152         mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION);
153 }
154
155