This patch allows specifying a per event sampling period or frequency.
Up until now, the same sampling period or frequency was applied to all
the events specified on the command line of perf record. A sampling 
period depends on the event, thus it is necessary to specify it per event.

With this patch, both the -F and -c options now take a comma separated
list of values. If a value is omitted for an event, it defaults to 1000Hz
frequency mode as before.

$ perf record -e cycles,instructions -c 100000,200000 -a -- sleep 5

Signed-off-by: Stephane Eranian <eran...@google.com>
---

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 9426383..28ea0a5 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -35,14 +35,10 @@ enum write_mode_t {
 
 static int                     *fd[MAX_NR_CPUS][MAX_COUNTERS];
 
-static u64                     user_interval                   = ULLONG_MAX;
-static u64                     default_interval                =      0;
-
 static int                     nr_cpus                         =      0;
 static unsigned int            page_size;
 static unsigned int            mmap_pages                      =    128;
-static unsigned int            user_freq                       = UINT_MAX;
-static int                     freq                            =   1000;
+static u64                     default_freq                    =   1000;
 static int                     output;
 static int                     pipe_output                     =      0;
 static const char              *output_name                    = "perf.data";
@@ -85,6 +81,97 @@ struct mmap_data {
 };
 
 static struct mmap_data                mmap_array[MAX_NR_CPUS];
+static u64                     user_periods[MAX_COUNTERS];
+static u64                     user_freqs[MAX_COUNTERS];
+static int                     nr_user_freqs;
+static int                     nr_user_periods;
+
+static int parse_user_freqs(const struct option *opt __used, const char *str,
+                 int unset __used)
+{
+       const char *p, *e, *eos = str + strlen(str);
+       int n = 0, ret = 0;
+       for (;;) {
+               p = strchr(str, ',');
+               e = p ? p : eos;
+
+               if (n == MAX_COUNTERS)
+                       goto error;
+               /* allow empty cgroups, i.e., skip */
+               if (e - str) {
+                       /* termination added */
+                       ret = sscanf(str, "%llu", user_freqs+n);
+                       if (ret != 1)
+                               goto error;
+                       if (!user_freqs[n])
+                               goto error_zero;
+                       if (user_periods[n])
+                               goto error_mix;
+                       nr_user_freqs++;
+               } else {
+                       user_freqs[n] = 0;
+               }
+               n++;
+               if (!p)
+                       break;
+               str = p+1;
+       }
+       return 0;
+error:
+       fprintf(stderr, "cannot parse event frequency %s\n", str);
+       return -1;
+error_zero:
+       fprintf(stderr, "invalid zero frequency, aborting");
+       return -1;
+error_mix:
+       fprintf(stderr, "event %d has both a frequency and period,"
+                       " must choose only one, aborting", n);
+       return -1;
+}
+
+static int parse_user_periods(const struct option *opt __used, const char *str,
+                 int unset __used)
+{
+       const char *p, *e, *eos = str + strlen(str);
+       int n = 0, ret;
+
+       for (;;) {
+               p = strchr(str, ',');
+               e = p ? p : eos;
+
+               if (n == MAX_COUNTERS)
+                       goto error;
+               /* allow empty cgroups, i.e., skip */
+               if (e - str) {
+                       /* termination added */
+                       ret = sscanf(str, "%llu", user_periods+n);
+                       if (ret != 1)
+                               goto error;
+                       if (!user_periods[n])
+                               goto error_zero;
+                       if (user_freqs[n])
+                               goto error_mix;
+                       nr_user_periods++;
+               } else {
+                       user_periods[n] = 0;
+               }
+               n++;
+               if (!p)
+                       break;
+               str = p+1;
+       }
+       return 0;
+error:
+       fprintf(stderr, "cannot parse event frequency %s\n", str);
+       return -1;
+error_zero:
+       fprintf(stderr, "invalid zero period, aborting");
+       return -1;
+error_mix:
+       fprintf(stderr, "event %d has both a frequency and period,"
+                       " must choose only one, aborting", n);
+       return -1;
+}
 
 static unsigned long mmap_read_head(struct mmap_data *md)
 {
@@ -232,6 +319,7 @@ static void create_counter(int counter, int cpu)
        struct perf_header_attr *h_attr;
        int track = !counter; /* only the first counter needs these */
        int thread_index;
+       u64 ufreq, uperiod;
        int ret;
        struct {
                u64 count;
@@ -249,18 +337,19 @@ static void create_counter(int counter, int cpu)
        if (nr_counters > 1)
                attr->sample_type |= PERF_SAMPLE_ID;
 
+       ufreq = user_freqs[counter];
+       uperiod = user_periods[counter];
        /*
-        * We default some events to a 1 default interval. But keep
+        * We default some events to a 1 default period. But keep
         * it a weak assumption overridable by the user.
         */
-       if (!attr->sample_period || (user_freq != UINT_MAX &&
-                                    user_interval != ULLONG_MAX)) {
-               if (freq) {
-                       attr->sample_type       |= PERF_SAMPLE_PERIOD;
-                       attr->freq              = 1;
-                       attr->sample_freq       = freq;
+       if (!attr->sample_period || ufreq != 0 || uperiod != 0) {
+               if (uperiod) {
+                       attr->sample_period = uperiod;
                } else {
-                       attr->sample_period = default_interval;
+                       attr->sample_type |= PERF_SAMPLE_PERIOD;
+                       attr->freq = 1;
+                       attr->sample_freq = ufreq ? ufreq : default_freq;
                }
        }
 
@@ -866,12 +955,14 @@ const struct option record_options[] = {
                    "list of cpus to monitor"),
        OPT_BOOLEAN('f', "force", &force,
                        "overwrite existing data file (deprecated)"),
-       OPT_U64('c', "count", &user_interval, "event period to sample"),
+       OPT_CALLBACK('c', "count", NULL, "period", "profile events at these "
+                         " periods", parse_user_periods),
        OPT_STRING('o', "output", &output_name, "file",
                    "output file name"),
        OPT_BOOLEAN('i', "no-inherit", &no_inherit,
                    "child tasks do not inherit counters"),
-       OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"),
+       OPT_CALLBACK('F', "freq", NULL, "freq", "profile events at these "
+                         " frequencies", parse_user_freqs),
        OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data 
pages"),
        OPT_BOOLEAN('g', "call-graph", &call_graph,
                    "do call-graph (stack chain/backtrace) recording"),
@@ -947,27 +1038,8 @@ int cmd_record(int argc, const char **argv, const char 
*prefix __used)
        if (!event_array)
                goto out_free_fd;
 
-       if (user_interval != ULLONG_MAX)
-               default_interval = user_interval;
-       if (user_freq != UINT_MAX)
-               freq = user_freq;
-
-       /*
-        * User specified count overrides default frequency.
-        */
-       if (default_interval)
-               freq = 0;
-       else if (freq) {
-               default_interval = freq;
-       } else {
-               fprintf(stderr, "frequency and count are zero, aborting\n");
-               err = -EINVAL;
-               goto out_free_event_array;
-       }
-
        err = __cmd_record(argc, argv);
 
-out_free_event_array:
        free(event_array);
 out_free_fd:
        for (i = 0; i < MAX_NR_CPUS; i++) {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 492d19d..c53cd10 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -543,7 +543,11 @@ static char *get_script_path(const char *script_root, 
const char *suffix)
 
 static bool is_top_script(const char *script_path)
 {
-       return ends_with((char *)script_path, "top") == NULL ? false : true;
+       char *str = strdup(script_path);
+       int ret;
+       ret = ends_with(str, "top") == NULL ? false : true;
+       free(str);
+       return ret;
 }
 
 static int has_required_arg(char *script_path)

------------------------------------------------------------------------------
Increase Visibility of Your 3D Game App & Earn a Chance To Win $500!
Tap into the largest installed PC base & get more eyes on your game by
optimizing for Intel(R) Graphics Technology. Get started today with the
Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs.
http://p.sf.net/sfu/intelisp-dev2dev
_______________________________________________
perfmon2-devel mailing list
perfmon2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/perfmon2-devel

Reply via email to