2 #include <mono/utils/mono-logger-internals.h>
3 #include <mono/utils/mono-proclib.h>
11 const char *event_name;
15 static NameAndMask event_list[] = {
16 { "domain", PROFLOG_DOMAIN_EVENTS },
17 { "assembly", PROFLOG_ASSEMBLY_EVENTS },
18 { "module", PROFLOG_MODULE_EVENTS },
19 { "class", PROFLOG_CLASS_EVENTS },
20 { "jit", PROFLOG_JIT_COMPILATION_EVENTS },
21 { "exception", PROFLOG_EXCEPTION_EVENTS },
22 { "gcalloc", PROFLOG_ALLOCATION_EVENTS },
23 { "gc", PROFLOG_GC_EVENTS },
24 { "thread", PROFLOG_THREAD_EVENTS },
25 { "calls", PROFLOG_CALL_EVENTS },
26 //{ "inscov", PROFLOG_INS_COVERAGE_EVENTS }, //this is a profiler API event, but there's no actual event for us to emit here
27 //{ "sampling", PROFLOG_SAMPLING_EVENTS }, //it makes no sense to enable/disable this event by itself
28 { "monitor", PROFLOG_MONITOR_EVENTS },
29 { "gcmove", PROFLOG_GC_MOVES_EVENTS },
30 { "gcroot", PROFLOG_GC_ROOT_EVENTS },
31 { "context", PROFLOG_CONTEXT_EVENTS },
32 { "finalization", PROFLOG_FINALIZATION_EVENTS },
33 { "counter", PROFLOG_COUNTER_EVENTS },
34 { "gchandle", PROFLOG_GC_HANDLE_EVENTS },
36 { "typesystem", PROFLOG_TYPELOADING_ALIAS },
37 { "coverage", PROFLOG_CODECOV_ALIAS },
38 //{ "sample", PROFLOG_PERF_SAMPLING_ALIAS }, //takes args, explicitly handles
39 { "alloc", PROFLOG_GC_ALLOC_ALIAS },
40 //{ "heapshot", PROFLOG_HEAPSHOT_ALIAS }, //takes args, explicitly handled
41 { "legacy", PROFLOG_LEGACY_ALIAS },
44 static void usage (void);
45 static void set_hsmode (ProfilerConfig *config, const char* val);
46 static void set_sample_freq (ProfilerConfig *config, const char *val);
49 match_option (const char *arg, const char *opt_name, const char **rval)
52 const char *end = strchr (arg, '=');
56 return !strcmp (arg, opt_name);
58 if (strncmp (arg, opt_name, strlen (opt_name)) || (end - arg) > strlen (opt_name) + 1)
63 //FIXME how should we handle passing a value to an arg that doesn't expect it?
64 return !strcmp (arg, opt_name);
69 parse_arg (const char *arg, ProfilerConfig *config)
73 if (match_option (arg, "help", NULL)) {
75 } else if (match_option (arg, "report", NULL)) {
76 config->do_report = TRUE;
77 } else if (match_option (arg, "debug", NULL)) {
78 config->do_debug = TRUE;
79 } else if (match_option (arg, "sampling-real", NULL)) {
80 config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_REAL;
81 } else if (match_option (arg, "sampling-process", NULL)) {
82 config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
83 } else if (match_option (arg, "heapshot", &val)) {
84 config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
85 set_hsmode (config, val);
86 } else if (match_option (arg, "sample", &val)) {
87 set_sample_freq (config, val);
88 if (config->sample_freq)
89 config->enable_mask |= PROFLOG_PERF_SAMPLING_ALIAS;
90 } else if (match_option (arg, "zip", NULL)) {
91 config->use_zip = TRUE;
92 } else if (match_option (arg, "output", &val)) {
93 config->output_filename = g_strdup (val);
94 } else if (match_option (arg, "port", &val)) {
96 config->command_port = strtoul (val, &end, 10);
97 } else if (match_option (arg, "maxframes", &val)) {
99 int num_frames = strtoul (val, &end, 10);
100 if (num_frames > MAX_FRAMES)
101 num_frames = MAX_FRAMES;
102 config->notraces = num_frames == 0;
103 config->num_frames = num_frames;
104 } else if (match_option (arg, "maxsamples", &val)) {
106 int max_samples = strtoul (val, &end, 10);
108 config->max_allocated_sample_hits = max_samples;
109 } else if (match_option (arg, "calldepth", &val)) {
111 config->max_call_depth = strtoul (val, &end, 10);
112 } else if (match_option (arg, "covfilter-file", &val)) {
113 if (config->cov_filter_files == NULL)
114 config->cov_filter_files = g_ptr_array_new ();
115 g_ptr_array_add (config->cov_filter_files, g_strdup (val));
119 for (i = 0; i < G_N_ELEMENTS (event_list); ++i){
120 if (!strcmp (arg, event_list [i].event_name)) {
121 config->enable_mask |= event_list [i].mask;
123 } else if (!strncmp (arg, "no", 2) && !strcmp (arg + 2, event_list [i].event_name)) {
124 config->disable_mask |= event_list [i].mask;
129 if (i == G_N_ELEMENTS (event_list))
130 mono_profiler_printf_err ("Could not parse argument: %s", arg);
135 load_args_from_env_or_default (ProfilerConfig *config)
137 //XXX change this to header constants
139 config->max_allocated_sample_hits = mono_cpu_count () * 1000;
140 config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
141 config->sample_freq = 100;
142 config->max_call_depth = 100;
143 config->num_frames = MAX_FRAMES;
148 proflog_parse_args (ProfilerConfig *config, const char *desc)
151 gboolean in_quotes = FALSE;
152 char quote_char = '\0';
153 char *buffer = malloc (strlen (desc));
156 load_args_from_env_or_default (config);
158 for (p = desc; *p; p++){
162 if (buffer_pos != 0){
163 buffer [buffer_pos] = 0;
164 parse_arg (buffer, config);
168 buffer [buffer_pos++] = *p;
174 buffer [buffer_pos++] = p[1];
181 if (quote_char == *p)
184 buffer [buffer_pos++] = *p;
191 buffer [buffer_pos++] = *p;
196 if (buffer_pos != 0) {
197 buffer [buffer_pos] = 0;
198 parse_arg (buffer, config);
203 //Compure config effective mask
204 config->effective_mask = config->enable_mask & ~config->disable_mask;
208 set_hsmode (ProfilerConfig *config, const char* val)
214 if (strcmp (val, "ondemand") == 0) {
215 config->hs_mode_ondemand = TRUE;
219 count = strtoul (val, &end, 10);
225 if (strcmp (end, "ms") == 0)
226 config->hs_mode_ms = count;
227 else if (strcmp (end, "gc") == 0)
228 config->hs_mode_gc = count;
234 set_sample_freq (ProfilerConfig *config, const char *val)
241 int freq = strtoul (val, &end, 10);
248 config->sample_freq = freq;
254 mono_profiler_printf ("Mono log profiler version %d.%d (format: %d)", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
255 mono_profiler_printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
256 mono_profiler_printf ("Options:");
257 mono_profiler_printf ("\thelp show this usage info");
258 mono_profiler_printf ("\t[no]'EVENT' enable/disable an individual profiling event");
259 mono_profiler_printf ("\t valid EVENT values:");
261 for (int i = 0; i < G_N_ELEMENTS (event_list); i++)
262 mono_profiler_printf ("\t %s", event_list [i].event_name);
264 mono_profiler_printf ("\t[no]typesystem enable/disable type system related events such as class and assembly loading");
265 mono_profiler_printf ("\t[no]alloc enable/disable recording allocation info");
266 mono_profiler_printf ("\t[no]calls enable/disable recording enter/leave method events (very heavy)");
267 mono_profiler_printf ("\t[no]legacy enable/disable pre mono 5.4 default profiler events");
268 mono_profiler_printf ("\tsample[=FREQ] enable/disable statistical sampling of threads (FREQ in Hz, 100 by default)");
269 mono_profiler_printf ("\theapshot[=MODE] record heapshot info (by default at each major collection)");
270 mono_profiler_printf ("\t MODE: every XXms milliseconds, every YYgc collections, ondemand");
271 mono_profiler_printf ("\t[no]coverage enable/disable collection of code coverage data");
272 mono_profiler_printf ("\tcovfilter=ASSEMBLY add ASSEMBLY to the code coverage filters");
273 mono_profiler_printf ("\t prefix a + to include the assembly or a - to exclude it");
274 mono_profiler_printf ("\t e.g. covfilter=-mscorlib");
275 mono_profiler_printf ("\tcovfilter-file=FILE use FILE to generate the list of assemblies to be filtered");
276 mono_profiler_printf ("\tmaxframes=NUM collect up to NUM stack frames");
277 mono_profiler_printf ("\tcalldepth=NUM ignore method events for call chain depth bigger than NUM");
278 mono_profiler_printf ("\toutput=FILENAME write the data to file FILENAME (the file is always overwritten)");
279 mono_profiler_printf ("\toutput=+FILENAME write the data to file FILENAME.pid (the file is always overwritten)");
280 mono_profiler_printf ("\toutput=|PROGRAM write the data to the stdin of PROGRAM");
281 mono_profiler_printf ("\t %%t is substituted with date and time, %%p with the pid");
282 mono_profiler_printf ("\treport create a report instead of writing the raw data to a file");
283 mono_profiler_printf ("\tzip compress the output data");
284 mono_profiler_printf ("\tport=PORTNUM use PORTNUM for the listening command server");