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 { "exception", PROFLOG_EXCEPTION_EVENTS },
17 { "monitor", PROFLOG_MONITOR_EVENTS },
18 { "gc", PROFLOG_GC_EVENTS },
19 { "gcalloc", PROFLOG_GC_ALLOCATION_EVENTS },
20 { "gcmove", PROFLOG_GC_MOVE_EVENTS },
21 { "gcroot", PROFLOG_GC_ROOT_EVENTS },
22 { "gchandle", PROFLOG_GC_HANDLE_EVENTS },
23 { "finalization", PROFLOG_GC_FINALIZATION_EVENTS },
24 { "counter", PROFLOG_COUNTER_EVENTS },
25 { "jit", PROFLOG_JIT_EVENTS },
27 { "alloc", PROFLOG_ALLOC_ALIAS },
28 { "legacy", PROFLOG_LEGACY_ALIAS },
31 static void usage (void);
32 static void set_hsmode (ProfilerConfig *config, const char* val);
33 static void set_sample_freq (ProfilerConfig *config, const char *val);
36 match_option (const char *arg, const char *opt_name, const char **rval)
39 const char *end = strchr (arg, '=');
43 return !strcmp (arg, opt_name);
45 if (strncmp (arg, opt_name, strlen (opt_name)) || (end - arg) > strlen (opt_name) + 1)
50 //FIXME how should we handle passing a value to an arg that doesn't expect it?
51 return !strcmp (arg, opt_name);
56 parse_arg (const char *arg, ProfilerConfig *config)
60 if (match_option (arg, "help", NULL)) {
62 } else if (match_option (arg, "report", NULL)) {
63 config->do_report = TRUE;
64 } else if (match_option (arg, "debug", NULL)) {
65 config->do_debug = TRUE;
66 } else if (match_option (arg, "heapshot", &val)) {
67 set_hsmode (config, val);
68 if (config->hs_mode != MONO_PROFILER_HEAPSHOT_NONE)
69 config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
70 } else if (match_option (arg, "heapshot-on-shutdown", NULL)) {
71 config->hs_on_shutdown = TRUE;
72 config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
73 } else if (match_option (arg, "sample", &val)) {
74 set_sample_freq (config, val);
75 config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
76 config->enable_mask |= PROFLOG_SAMPLE_EVENTS;
77 } else if (match_option (arg, "sample-real", &val)) {
78 set_sample_freq (config, val);
79 config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_REAL;
80 config->enable_mask |= PROFLOG_SAMPLE_EVENTS;
81 } else if (match_option (arg, "calls", NULL)) {
82 config->enter_leave = TRUE;
83 } else if (match_option (arg, "coverage", NULL)) {
84 g_warning ("the log profiler support for code coverage is obsolete, use the \"coverage\" profiler");
85 config->collect_coverage = TRUE;
86 } else if (match_option (arg, "zip", NULL)) {
87 config->use_zip = TRUE;
88 } else if (match_option (arg, "output", &val)) {
89 config->output_filename = g_strdup (val);
90 } else if (match_option (arg, "port", &val)) {
92 config->command_port = strtoul (val, &end, 10);
93 } else if (match_option (arg, "maxframes", &val)) {
95 int num_frames = strtoul (val, &end, 10);
96 if (num_frames > MAX_FRAMES)
97 num_frames = MAX_FRAMES;
98 config->num_frames = num_frames;
99 } else if (match_option (arg, "maxsamples", &val)) {
101 int max_samples = strtoul (val, &end, 10);
103 config->max_allocated_sample_hits = max_samples;
104 } else if (match_option (arg, "calldepth", &val)) {
106 config->max_call_depth = strtoul (val, &end, 10);
107 } else if (match_option (arg, "callspec", &val)) {
112 char *spec = g_strdup (val);
113 size_t speclen = strlen (val);
114 if (speclen > 0 && spec[speclen - 1] == '\"')
115 spec[speclen - 1] = '\0';
117 if (!mono_callspec_parse (spec, &config->callspec, &errstr)) {
118 mono_profiler_printf_err (
119 "Could not parse callspec: '%s': %s", spec,
122 mono_callspec_cleanup (&config->callspec);
125 } else if (match_option (arg, "covfilter-file", &val)) {
126 if (config->cov_filter_files == NULL)
127 config->cov_filter_files = g_ptr_array_new ();
128 g_ptr_array_add (config->cov_filter_files, g_strdup (val));
132 for (i = 0; i < G_N_ELEMENTS (event_list); ++i){
133 if (!strcmp (arg, event_list [i].event_name)) {
134 config->enable_mask |= event_list [i].mask;
136 } else if (!strncmp (arg, "no", 2) && !strcmp (arg + 2, event_list [i].event_name)) {
137 config->disable_mask |= event_list [i].mask;
142 if (i == G_N_ELEMENTS (event_list))
143 mono_profiler_printf_err ("Could not parse argument: %s", arg);
148 load_args_from_env_or_default (ProfilerConfig *config)
150 //XXX change this to header constants
152 config->max_allocated_sample_hits = mono_cpu_count () * 1000;
153 config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
154 config->sample_freq = 100;
155 config->max_call_depth = 100;
156 config->num_frames = MAX_FRAMES;
161 proflog_parse_args (ProfilerConfig *config, const char *desc)
164 gboolean in_quotes = FALSE;
165 char quote_char = '\0';
166 char *buffer = malloc (strlen (desc));
169 load_args_from_env_or_default (config);
171 for (p = desc; *p; p++){
175 if (buffer_pos != 0){
176 buffer [buffer_pos] = 0;
177 parse_arg (buffer, config);
181 buffer [buffer_pos++] = *p;
187 buffer [buffer_pos++] = p[1];
194 if (quote_char == *p)
197 buffer [buffer_pos++] = *p;
204 buffer [buffer_pos++] = *p;
209 if (buffer_pos != 0) {
210 buffer [buffer_pos] = 0;
211 parse_arg (buffer, config);
216 //Compure config effective mask
217 config->effective_mask = config->enable_mask & ~config->disable_mask;
221 set_hsmode (ProfilerConfig *config, const char* val)
224 config->hs_mode = MONO_PROFILER_HEAPSHOT_MAJOR;
228 if (strcmp (val, "ondemand") == 0) {
229 config->hs_mode = MONO_PROFILER_HEAPSHOT_ON_DEMAND;
235 unsigned int count = strtoul (val, &end, 10);
242 if (strcmp (end, "ms") == 0) {
243 config->hs_mode = MONO_PROFILER_HEAPSHOT_X_MS;
244 config->hs_freq_ms = count;
245 } else if (strcmp (end, "gc") == 0) {
246 config->hs_mode = MONO_PROFILER_HEAPSHOT_X_GC;
247 config->hs_freq_gc = count;
253 set_sample_freq (ProfilerConfig *config, const char *val)
260 int freq = strtoul (val, &end, 10);
267 config->sample_freq = freq;
273 mono_profiler_printf ("Mono log profiler version %d.%d (format: %d)", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
274 mono_profiler_printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
275 mono_profiler_printf ("Options:");
276 mono_profiler_printf ("\thelp show this usage info");
277 mono_profiler_printf ("\t[no]'EVENT' enable/disable an individual profiling event");
278 mono_profiler_printf ("\t valid EVENT values:");
280 for (int i = 0; i < G_N_ELEMENTS (event_list); i++)
281 mono_profiler_printf ("\t %s", event_list [i].event_name);
283 mono_profiler_printf ("\t[no]alloc enable/disable recording allocation info");
284 mono_profiler_printf ("\t[no]legacy enable/disable pre Mono 5.6 default profiler events");
285 mono_profiler_printf ("\tsample[-real][=FREQ] enable/disable statistical sampling of threads");
286 mono_profiler_printf ("\t FREQ in Hz, 100 by default");
287 mono_profiler_printf ("\t the -real variant uses wall clock time instead of process time");
288 mono_profiler_printf ("\theapshot[=MODE] record heapshot info (by default at each major collection)");
289 mono_profiler_printf ("\t MODE: every XXms milliseconds, every YYgc collections, ondemand");
290 mono_profiler_printf ("\theapshot-on-shutdown do a heapshot on runtime shutdown");
291 mono_profiler_printf ("\t this option is independent of the above option");
292 mono_profiler_printf ("\tcalls enable recording enter/leave method events (very heavy)");
293 mono_profiler_printf ("\tcoverage enable collection of code coverage data");
294 mono_profiler_printf ("\tcovfilter=ASSEMBLY add ASSEMBLY to the code coverage filters");
295 mono_profiler_printf ("\t prefix a + to include the assembly or a - to exclude it");
296 mono_profiler_printf ("\t e.g. covfilter=-mscorlib");
297 mono_profiler_printf ("\tcovfilter-file=FILE use FILE to generate the list of assemblies to be filtered");
298 mono_profiler_printf ("\tmaxframes=NUM collect up to NUM stack frames");
299 mono_profiler_printf ("\tcalldepth=NUM ignore method events for call chain depth bigger than NUM");
300 mono_profiler_printf ("\toutput=FILENAME write the data to file FILENAME (the file is always overwritten)");
301 mono_profiler_printf ("\toutput=+FILENAME write the data to file FILENAME.pid (the file is always overwritten)");
302 mono_profiler_printf ("\toutput=|PROGRAM write the data to the stdin of PROGRAM");
303 mono_profiler_printf ("\t %%t is substituted with date and time, %%p with the pid");
304 mono_profiler_printf ("\treport create a report instead of writing the raw data to a file");
305 mono_profiler_printf ("\tzip compress the output data");
306 mono_profiler_printf ("\tport=PORTNUM use PORTNUM for the listening command server");