+/*
+ * Context type for command line option parsing.
+ */
+struct ctx_type {
+ int type;
+ struct cds_list_head list;
+};
+
+/*
+ * Perf counter type
+ */
+static struct ctx_perf_type {
+ enum perf_type value;
+ char *symbol;
+} ctx_perf_type[] = {
+ { PERF_TYPE_HARDWARE, "hw" },
+ { PERF_TYPE_SOFTWARE, "sw" },
+};
+
+/*
+ * Perf counter IDs
+ */
+static struct ctx_perf {
+ enum perf_type type;
+ union {
+ enum perf_count_hard hard;
+ enum perf_count_soft soft;
+ } id;
+ char *symbol;
+} ctx_perf[] = {
+ /* Hardware counter */
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_CPU_CYCLES, "cpu_cycles" },
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_INSTRUCTIONS, "instr" },
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_CACHE_REFERENCES, "cache_refs" },
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_CACHE_MISSES, "cache_miss" },
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch_instr" },
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_BRANCH_MISSES, "branch_miss" },
+ { PERF_TYPE_HARDWARE, .id.hard = PERF_COUNT_HW_BUS_CYCLES, "bus_cycles" },
+ /* Sofware counter */
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_CPU_CLOCK, "cpu_clock" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_TASK_CLOCK, "task_clock" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_PAGE_FAULTS, "page_faults" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_CONTEXT_SWITCHES, "ctx_switches" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_CPU_MIGRATIONS, "cpu_migration" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_PAGE_FAULTS_MIN, "page_faults_minor" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_PAGE_FAULTS_MAJ, "page_faults_major" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_ALIGNMENT_FAULTS, "align_faults" },
+ { PERF_TYPE_SOFTWARE, .id.soft = PERF_COUNT_SW_EMULATION_FAULTS, "emu_faults" },
+ /* Closure */
+ { -1, .id.hard = -1 , NULL },
+};
+
+/*
+ * Context options
+ */
+static struct ctx_opts {
+ enum context_type value;
+ char *symbol;
+} ctx_opts[] = {
+ { CONTEXT_PID, "pid" },
+ { CONTEXT_PERF_COUNTER, "perf" },
+ { CONTEXT_COMM, "comm" },
+ { CONTEXT_PRIO, "prio" },
+ { CONTEXT_NICE, "nice" },
+ { CONTEXT_VPID, "vpid" },
+ { CONTEXT_TID, "tid" },
+ { CONTEXT_VTID, "vtid" },
+ { CONTEXT_PPID, "ppid" },
+ { CONTEXT_VPPID, "vppid" },
+ { -1, NULL }, /* Closure */
+};
+
+/*
+ * List of context type. Use to enable multiple context on a single command
+ * line entry.
+ */
+struct ctx_type_list {
+ struct cds_list_head head;
+} ctx_type_list = {
+ .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
+};
+
+/*
+ * Pretty print perf type.
+ */
+static void print_perf_type(FILE *ofp)
+{
+ fprintf(ofp, " ");
+ fprintf(ofp, "%s = %d, ", ctx_perf_type[0].symbol, ctx_perf_type[0].value);
+ fprintf(ofp, "%s = %d\n", ctx_perf_type[1].symbol, ctx_perf_type[1].value);
+}
+
+/*
+ * Pretty print context type.
+ */
+static void print_ctx_type(FILE *ofp)
+{
+ int i = 0;
+
+ fprintf(ofp, " ");
+ while (ctx_opts[i].symbol != NULL) {
+ fprintf(ofp, "%s = %d, ", ctx_opts[i].symbol, ctx_opts[i].value);
+ i++;
+ if (!(i%3)) {
+ fprintf(ofp, "\n ");
+ }
+ }
+}
+
+/*
+ * Pretty print perf hardware counter.
+ */
+static void print_perf_hw(FILE *ofp)
+{
+ int i = 0, count = 0;
+
+ fprintf(ofp, " ");
+ while (ctx_perf[i].symbol != NULL) {
+ if (ctx_perf[i].type == PERF_TYPE_HARDWARE) {
+ fprintf(ofp, "%s = %d, ", ctx_perf[i].symbol, ctx_perf[i].id.hard);
+ count++;
+ if (!(count % 3)) {
+ fprintf(ofp, "\n ");
+ }
+ }
+ i++;
+ }
+ fprintf(ofp, "\n");
+}
+
+/*
+ * Pretty print perf software counter.
+ */
+static void print_perf_sw(FILE *ofp)
+{
+ int i = 0, count = 0;
+
+ fprintf(ofp, " ");
+ while (ctx_perf[i].symbol != NULL) {
+ if (ctx_perf[i].type == PERF_TYPE_SOFTWARE) {
+ fprintf(ofp, "%s = %d, ", ctx_perf[i].symbol, ctx_perf[i].id.soft);
+ count++;
+ if (!(count % 3)) {
+ fprintf(ofp, "\n ");
+ }
+ }
+ i++;
+ }
+ fprintf(ofp, "\n");
+}
+