}
 }
 
-static void apply_config_terms(struct perf_evsel *evsel)
+static void
+perf_evsel__reset_callgraph(struct perf_evsel *evsel,
+                           struct callchain_param *param)
+{
+       struct perf_event_attr *attr = &evsel->attr;
+
+       perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
+       if (param->record_mode == CALLCHAIN_LBR) {
+               perf_evsel__reset_sample_bit(evsel, BRANCH_STACK);
+               attr->branch_sample_type &= ~(PERF_SAMPLE_BRANCH_USER |
+                                             PERF_SAMPLE_BRANCH_CALL_STACK);
+       }
+       if (param->record_mode == CALLCHAIN_DWARF) {
+               perf_evsel__reset_sample_bit(evsel, REGS_USER);
+               perf_evsel__reset_sample_bit(evsel, STACK_USER);
+       }
+}
+
+static void apply_config_terms(struct perf_evsel *evsel,
+                              struct record_opts *opts)
 {
        struct perf_evsel_config_term *term;
        struct list_head *config_terms = &evsel->config_terms;
        struct perf_event_attr *attr = &evsel->attr;
+       struct callchain_param param;
+       u32 dump_size = 0;
+       char *callgraph_buf = NULL;
+
+       /* callgraph default */
+       param.record_mode = callchain_param.record_mode;
 
        list_for_each_entry(term, config_terms, list) {
                switch (term->type) {
                        else
                                perf_evsel__reset_sample_bit(evsel, TIME);
                        break;
+               case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
+                       callgraph_buf = term->val.callgraph;
+                       break;
+               case PERF_EVSEL__CONFIG_TERM_STACK_USER:
+                       dump_size = term->val.stack_user;
+                       break;
                default:
                        break;
                }
        }
+
+       /* User explicitly set per-event callgraph, clear the old setting and reset. */
+       if ((callgraph_buf != NULL) || (dump_size > 0)) {
+
+               /* parse callgraph parameters */
+               if (callgraph_buf != NULL) {
+                       param.enabled = true;
+                       if (parse_callchain_record(callgraph_buf, ¶m)) {
+                               pr_err("per-event callgraph setting for %s failed. "
+                                      "Apply callgraph global setting for it\n",
+                                      evsel->name);
+                               return;
+                       }
+               }
+               if (dump_size > 0) {
+                       dump_size = round_up(dump_size, sizeof(u64));
+                       param.dump_size = dump_size;
+               }
+
+               /* If global callgraph set, clear it */
+               if (callchain_param.enabled)
+                       perf_evsel__reset_callgraph(evsel, &callchain_param);
+
+               /* set perf-event callgraph */
+               if (param.enabled)
+                       perf_evsel__config_callgraph(evsel, opts, ¶m);
+       }
 }
 
 /*
         * Apply event specific term settings,
         * it overloads any global configuration.
         */
-       apply_config_terms(evsel);
+       apply_config_terms(evsel, opts);
 }
 
 static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
 
                        return -EINVAL;
                }
                break;
+       case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
+               CHECK_TYPE_VAL(STR);
+               break;
+       case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
+               CHECK_TYPE_VAL(NUM);
+               break;
        case PARSE_EVENTS__TERM_TYPE_NAME:
                CHECK_TYPE_VAL(STR);
                break;
                case PARSE_EVENTS__TERM_TYPE_TIME:
                        ADD_CONFIG_TERM(TIME, time, term->val.num);
                        break;
+               case PARSE_EVENTS__TERM_TYPE_CALLGRAPH:
+                       ADD_CONFIG_TERM(CALLGRAPH, callgraph, term->val.str);
+                       break;
+               case PARSE_EVENTS__TERM_TYPE_STACKSIZE:
+                       ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num);
+                       break;
                default:
                        break;
                }
 
 {
        struct perf_pmu_format *format;
        char *err, *str;
-       static const char *static_terms = "config,config1,config2,name,period,freq,branch_type,time\n";
+       static const char *static_terms = "config,config1,config2,name,"
+                                         "period,freq,branch_type,time,"
+                                         "call-graph,stack-size\n";
        unsigned i = 0;
 
        if (!asprintf(&str, "valid terms:"))