Log profiler: allow overwriting data files and name them from date and pid.
authorPaolo Molaro <lupus@oddwiz.org>
Fri, 12 Nov 2010 17:22:03 +0000 (18:22 +0100)
committerPaolo Molaro <lupus@oddwiz.org>
Fri, 12 Nov 2010 20:38:04 +0000 (21:38 +0100)
* utils.h, utils.c: added getpid() wrapper.
* decode.c: display the program pid if available.
* proflog.c: added substitutions for the output name, change the default
behaviour to not overwrite a file and allow '-' at the start of the
file name to force overwrite.

mono/profiler/decode.c
mono/profiler/log-profiler.txt
mono/profiler/proflog.c
mono/profiler/utils.c
mono/profiler/utils.h

index 0a33040a73dad76eee8e08ed67ef3ae928c7d3cf..37b88878cf3beefa7c8b010e76f0fac59e61c0e1 100644 (file)
@@ -622,6 +622,7 @@ typedef struct {
        int version_major;
        int version_minor;
        int timer_overhead;
+       int pid;
        uint64_t startup_time;
        ThreadContext *threads;
        ThreadContext *current;
@@ -1480,6 +1481,7 @@ load_file (char *name)
                return NULL;
        ctx->startup_time = read_int64 (p + 8);
        ctx->timer_overhead = read_int32 (p + 16);
+       ctx->pid = read_int32 (p + 24);
        return ctx;
 }
 
@@ -1518,7 +1520,9 @@ dump_header (ProfContext *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
index 0d6349b6f248af16781e38b0e2d417a073457374..8fcc602bcde7adaa824f23dd93f9e07804b0c6c6 100644 (file)
@@ -107,10 +107,14 @@ bigger than NUM.
 * *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 -`.
index 06720a3b91536742795d54c2ddc0512c15f82ae2..7d7f9320de8a57bf373ac9f8054423a0eb95c2b2 100644 (file)
@@ -265,6 +265,15 @@ static __thread LogBuffer* tlsbuffer = NULL;
 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)
 {
@@ -408,7 +417,7 @@ dump_header (MonoProfiler *profiler)
        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) {
@@ -963,25 +972,100 @@ log_shutdown (MonoProfiler *prof)
        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)
@@ -1006,8 +1090,9 @@ usage (int do_exit)
        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)
@@ -1174,6 +1259,8 @@ mono_profiler_startup (const char *desc)
        utils_init (fast_time);
 
        prof = create_profiler (filename);
+       if (!prof)
+               return;
        init_thread ();
 
        mono_profiler_install (prof, log_shutdown);
index b16e9bfc6aa7474e61a40ec7075fc349eb6a30ea..8bf57a72f7c10e0e68e48ef63215d79e455a1a1c 100644 (file)
@@ -18,6 +18,7 @@
 #include <time.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 #ifdef HOST_WIN32
 #include <windows.h>
 #else
@@ -412,3 +413,13 @@ thread_id (void)
 #endif
 }
 
+uintptr_t
+process_id (void)
+{
+#ifdef HOST_WIN32
+       return 0; /* FIXME */
+#else
+       return (uintptr_t)getpid ();
+#endif
+}
+
index fd104ad4fca763d81e3c02dbba91ff92184c5cd9..3af56d202c6c4c07e129b42377669db3fe2d9500 100644 (file)
@@ -12,6 +12,7 @@ void free_buffer (void *buf, int size);
 void take_lock (void);
 void release_lock (void);
 uintptr_t thread_id (void);
+uintptr_t process_id (void);
 
 void encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf);
 void encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf);