target: enhance target profiling
authorHsiangkai Wang <hsiangkai@gmail.com>
Wed, 14 Aug 2013 06:46:58 +0000 (14:46 +0800)
committerSpencer Oliver <spen@spen-soft.co.uk>
Fri, 13 Sep 2013 19:37:14 +0000 (19:37 +0000)
1. gprof uses 2-bytes as minimum bucket size.
2. As user wants to use gprof --sum to summarize multiple
   profiling data files, the range MUST be the same.
   Add new arguments to specify profiling range.

Change-Id: Ie7e6afa6a4d82250e2d194a0eed2b428c1479ea1
Signed-off-by: Hsiangkai Wang <hsiangkai@gmail.com>
Reviewed-on: http://openocd.zylin.com/1572
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/target/target.c

index b038519732d92c9b63761351c9dfda719728bbc9..9cc94f3a09782f73750f5148c1f827b10b1b7ac3 100644 (file)
@@ -3426,8 +3426,11 @@ static void writeString(FILE *f, char *s)
        writeData(f, s, strlen(s));
 }
 
+typedef unsigned char UNIT[2];  /* unit of profiling */
+
 /* Dump a gmon.out histogram file. */
-static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename)
+static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename,
+               bool with_range, uint32_t start_address, uint32_t end_address)
 {
        uint32_t i;
        FILE *f = fopen(filename, "w");
@@ -3443,18 +3446,25 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena
        writeData(f, &zero, 1);
 
        /* figure out bucket size */
-       uint32_t min = samples[0];
-       uint32_t max = samples[0];
-       for (i = 0; i < sampleNum; i++) {
-               if (min > samples[i])
-                       min = samples[i];
-               if (max < samples[i])
-                       max = samples[i];
-       }
+       uint32_t min;
+       uint32_t max;
+       if (with_range) {
+               min = start_address;
+               max = end_address;
+       } else {
+               min = samples[0];
+               max = samples[0];
+               for (i = 0; i < sampleNum; i++) {
+                       if (min > samples[i])
+                               min = samples[i];
+                       if (max < samples[i])
+                               max = samples[i];
+               }
 
-       /* max should be (largest sample + 1)
-        * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */
-       max++;
+               /* max should be (largest sample + 1)
+                * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */
+               max++;
+       }
 
        int addressSpace = max - min;
        assert(addressSpace >= 2);
@@ -3462,7 +3472,7 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena
        /* FIXME: What is the reasonable number of buckets?
         * The profiling result will be more accurate if there are enough buckets. */
        static const uint32_t maxBuckets = 128 * 1024; /* maximum buckets. */
-       uint32_t numBuckets = addressSpace;
+       uint32_t numBuckets = addressSpace / sizeof(UNIT);
        if (numBuckets > maxBuckets)
                numBuckets = maxBuckets;
        int *buckets = malloc(sizeof(int) * numBuckets);
@@ -3473,6 +3483,10 @@ static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filena
        memset(buckets, 0, sizeof(int) * numBuckets);
        for (i = 0; i < sampleNum; i++) {
                uint32_t address = samples[i];
+
+               if ((address < min) || (max <= address))
+                       continue;
+
                long long a = address - min;
                long long b = numBuckets;
                long long c = addressSpace;
@@ -3517,7 +3531,7 @@ COMMAND_HANDLER(handle_profile_command)
 {
        struct target *target = get_current_target(CMD_CTX);
 
-       if (CMD_ARGC != 2)
+       if ((CMD_ARGC != 2) && (CMD_ARGC != 4))
                return ERROR_COMMAND_SYNTAX_ERROR;
 
        const uint32_t MAX_PROFILE_SAMPLE_NUM = 10000;
@@ -3565,7 +3579,17 @@ COMMAND_HANDLER(handle_profile_command)
                return retval;
        }
 
-       write_gmon(samples, num_of_sampels, CMD_ARGV[1]);
+       uint32_t start_address = 0;
+       uint32_t end_address = 0;
+       bool with_range = false;
+       if (CMD_ARGC == 4) {
+               with_range = true;
+               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], start_address);
+               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], end_address);
+       }
+
+       write_gmon(samples, num_of_sampels, CMD_ARGV[1],
+                       with_range, start_address, end_address);
        command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
 
        free(samples);
@@ -5563,7 +5587,7 @@ static const struct command_registration target_exec_command_handlers[] = {
                .name = "profile",
                .handler = handle_profile_command,
                .mode = COMMAND_EXEC,
-               .usage = "seconds filename",
+               .usage = "seconds filename [start end]",
                .help = "profiling samples the CPU PC",
        },
        /** @todo don't register virt2phys() unless target supports it */