perf record: Provide default branch stack sampling mode option

This patch chanegs the logic of the -b, --branch-stack options
of perf record.

Based on users' request, the patch provides a default filter
mode with the -b (or --branch-any) option.  With the option,
any type of taken branches is sampled.

With -j (or --branch-filter), the user can specify any
valid combination of branch types and privilege levels
if supported by the underlying hardware.

The -b (--branch any) is a shortcut for: --branch-filter any.

 $ perf record -b foo

or:

 $ perf record --branch-filter any foo

For more specific filtering:

 $ perf record --branch-filter ind_call,u foo

Signed-off-by: Stephane Eranian <eranian@google.com>
Cc: peterz@infradead.org
Cc: acme@redhat.com
Cc: asharma@fb.com
Cc: ravitillo@lbl.gov
Cc: vweaver1@eecs.utk.edu
Cc: khandual@linux.vnet.ibm.com
Cc: dsahern@gmail.com
Link: http://lkml.kernel.org/r/1331246868-19905-2-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 1c49d4e..a7c53a9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -660,7 +660,7 @@
 };
 
 static int
-parse_branch_stack(const struct option *opt, const char *str, int unset __used)
+parse_branch_stack(const struct option *opt, const char *str, int unset)
 {
 #define ONLY_PLM \
 	(PERF_SAMPLE_BRANCH_USER	|\
@@ -669,40 +669,53 @@
 
 	uint64_t *mode = (uint64_t *)opt->value;
 	const struct branch_mode *br;
-	char *s, *os, *p;
+	char *s, *os = NULL, *p;
 	int ret = -1;
 
-	*mode = 0;
+	if (unset)
+		return 0;
 
-	/* because str is read-only */
-	s = os = strdup(str);
-	if (!s)
+	/*
+	 * cannot set it twice, -b + --branch-filter for instance
+	 */
+	if (*mode)
 		return -1;
 
-	for (;;) {
-		p = strchr(s, ',');
-		if (p)
-			*p = '\0';
+	/* str may be NULL in case no arg is passed to -b */
+	if (str) {
+		/* because str is read-only */
+		s = os = strdup(str);
+		if (!s)
+			return -1;
 
-		for (br = branch_modes; br->name; br++) {
-			if (!strcasecmp(s, br->name))
+		for (;;) {
+			p = strchr(s, ',');
+			if (p)
+				*p = '\0';
+
+			for (br = branch_modes; br->name; br++) {
+				if (!strcasecmp(s, br->name))
+					break;
+			}
+			if (!br->name) {
+				ui__warning("unknown branch filter %s,"
+					    " check man page\n", s);
+				goto error;
+			}
+
+			*mode |= br->mode;
+
+			if (!p)
 				break;
+
+			s = p + 1;
 		}
-		if (!br->name)
-			goto error;
-
-		*mode |= br->mode;
-
-		if (!p)
-			break;
-
-		s = p + 1;
 	}
 	ret = 0;
 
+	/* default to any branch */
 	if ((*mode & ~ONLY_PLM) == 0) {
-		error("need at least one branch type with -b\n");
-		ret = -1;
+		*mode = PERF_SAMPLE_BRANCH_ANY;
 	}
 error:
 	free(os);
@@ -798,8 +811,13 @@
 		     "monitor event in cgroup name only",
 		     parse_cgroups),
 	OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
-	OPT_CALLBACK('b', "branch-stack", &record.opts.branch_stack,
-		     "branch mode mask", "branch stack sampling modes",
+
+	OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
+		     "branch any", "sample any taken branches",
+		     parse_branch_stack),
+
+	OPT_CALLBACK('j', "branch-filter", &record.opts.branch_stack,
+		     "branch filter mask", "branch stack filter modes",
 		     parse_branch_stack),
 	OPT_END()
 };