int version_major;
int version_minor;
int timer_overhead;
+ int pid;
uint64_t startup_time;
ThreadContext *threads;
ThreadContext *current;
return NULL;
ctx->startup_time = read_int64 (p + 8);
ctx->timer_overhead = read_int32 (p + 16);
+ ctx->pid = read_int32 (p + 24);
return ctx;
}
fprintf (outfile, "\tProfiler version: %d.%d\n", ctx->version_major, ctx->version_minor);
fprintf (outfile, "\tData version: %d\n", ctx->data_version);
fprintf (outfile, "\tMean timer overhead: %d nanoseconds\n", ctx->timer_overhead);
- fprintf (outfile, "\tProgram startup: %s\n", t);
+ fprintf (outfile, "\tProgram startup: %s", t);
+ if (ctx->pid)
+ fprintf (outfile, "\tProgram ID: %d\n", ctx->pid);
}
static void
* *zip*: automatically compress the output data in gzip format.
* *output=OUTSPEC*: instead of writing the profiling data to the output.mlpd file,
-do according to *OUTSPEC*:
+substitute *%p* in *OUTSPEC* with the current process id and *%t* with the current
+date and time, then do according to *OUTSPEC*:
* if *OUTSPEC* begins with a *|* character, execute the rest as a program
and feed the data to its standard input
- * otherwise write the data the the named file
+ * if *OUTSPEC* begins with a *-* character, use the rest of OUTSPEC as
+ the filename, but force overwrite any existing file by that name
+ * otherwise write the data the the named file: note that is a file by that
+ name already exists, a warning is issued and profiling is disabled.
* *report*: the profiling data is sent to mprof-report, which will print a summary
report. This is equivalent to the option: `output=mprof-report -`.
static pthread_key_t tlsbuffer;
#endif
+static char*
+pstrdup (const char *s)
+{
+ int len = strlen (s) + 1;
+ char *p = malloc (len);
+ memcpy (p, s, len);
+ return p;
+}
+
static LogBuffer*
create_buffer (void)
{
p = write_int64 (p, ((uint64_t)time (NULL)) * 1000); /* startup time */
p = write_int32 (p, get_timer_overhead ()); /* timer overhead */
p = write_int32 (p, 0); /* flags */
- p = write_int32 (p, 0); /* pid */
+ p = write_int32 (p, process_id ()); /* pid */
p = write_int32 (p, 0); /* opsystem */
#if defined (HAVE_SYS_ZLIB)
if (profiler->gzfile) {
free (prof);
}
+static char*
+new_filename (const char* filename)
+{
+ time_t t = time (NULL);
+ int pid = process_id ();
+ char pid_buf [16];
+ char time_buf [16];
+ char *res, *d;
+ const char *p;
+ int count_dates = 0;
+ int count_pids = 0;
+ int s_date, s_pid;
+ struct tm *ts;
+ for (p = filename; *p; p++) {
+ if (*p != '%')
+ continue;
+ p++;
+ if (*p == 't')
+ count_dates++;
+ else if (*p == 'p')
+ count_pids++;
+ else if (*p == 0)
+ break;
+ }
+ if (!count_dates && !count_pids)
+ return pstrdup (filename);
+ snprintf (pid_buf, sizeof (pid_buf), "%d", pid);
+ ts = gmtime (&t);
+ snprintf (time_buf, sizeof (time_buf), "%d%02d%02d%02d%02d%02d",
+ 1900 + ts->tm_year, 1 + ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec);
+ s_date = strlen (time_buf);
+ s_pid = strlen (pid_buf);
+ d = res = malloc (strlen (filename) + s_date * count_dates + s_pid * count_pids);
+ for (p = filename; *p; p++) {
+ if (*p != '%') {
+ *d++ = *p;
+ continue;
+ }
+ p++;
+ if (*p == 't') {
+ strcpy (d, time_buf);
+ d += s_date;
+ continue;
+ } else if (*p == 'p') {
+ strcpy (d, pid_buf);
+ d += s_pid;
+ continue;
+ } else if (*p == '%') {
+ *d++ = '%';
+ continue;
+ } else if (*p == 0)
+ break;
+ *d++ = '%';
+ *d++ = *p;
+ }
+ *d = 0;
+ return res;
+}
+
static MonoProfiler*
create_profiler (const char *filename)
{
MonoProfiler *prof;
+ char *nf;
+ int force_delete = 0;
prof = calloc (1, sizeof (MonoProfiler));
if (do_report) /* FIXME: use filename as output */
filename = "|mprof-report -";
if (!filename)
filename = "output.mlpd";
- if (*filename == '|') {
- prof->file = popen (filename + 1, "w");
+ if (*filename == '-') {
+ force_delete = 1;
+ filename++;
+ }
+ nf = new_filename (filename);
+ if (*nf == '|') {
+ prof->file = popen (nf + 1, "w");
prof->pipe_output = 1;
} else {
- unlink (filename);
- prof->file = fopen (filename, "wb");
+ FILE *f;
+ if (force_delete)
+ unlink (nf);
+ if ((f = fopen (nf, "r"))) {
+ fclose (f);
+ fprintf (stderr, "The Mono profiler won't overwrite existing filename: %s.\n", nf);
+ fprintf (stderr, "Profiling disabled: use a different name or -FILENAME to force overwrite.\n");
+ free (prof);
+ return NULL;
+ }
+ prof->file = fopen (nf, "wb");
}
if (!prof->file) {
- printf ("Cannot create profiler output: %s\n", filename);
+ printf ("Cannot create profiler output: %s\n", nf);
exit (1);
}
#if defined (HAVE_SYS_ZLIB)
printf ("\ttime=fast use a faster (but more inaccurate) timer\n");
printf ("\tmaxframes=NUM collect up to NUM stack frames\n");
printf ("\tcalldepth=NUM ignore method events for call chain depth bigger than NUM\n");
- printf ("\toutput=FILENAME write the data to file FILENAME\n");
+ printf ("\toutput=FILENAME write the data to file FILENAME (-FILENAME to overwrite)\n");
printf ("\toutput=|PROGRAM write the data to the stdin of PROGRAM\n");
+ printf ("\t %%t is subtituted with date and time, %%p with the pid\n");
printf ("\treport create a report instead of writing the raw data to a file\n");
printf ("\tzip compress the output data\n");
if (do_exit)
utils_init (fast_time);
prof = create_profiler (filename);
+ if (!prof)
+ return;
init_thread ();
mono_profiler_install (prof, log_shutdown);