Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf evlist: Setup backward mmap state machine

Introduce a bkw_mmap_state state machine to evlist:

.________________(forbid)_____________.
| V
NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY
^ ^ | ^ |
| |__(forbid)____/ |___(forbid)___/|
| |
\_________________(3)_______________/

NOTREADY : Backward ring buffers are not ready
RUNNING : Backward ring buffers are recording
DATA_PENDING : We are required to collect data from backward ring buffers
EMPTY : We have collected data from backward ring buffers.

(0): Setup backward ring buffer
(1): Pause ring buffers for reading
(2): Read from ring buffers
(3): Resume ring buffers for recording

We can't avoid this complexity. Since we deliberately drop records from
overwritable ring buffer, there's no way for us to check remaining from
ring buffer itself (by checking head and old pointers). Therefore, we
need DATA_PENDING and EMPTY state to help us recording what we have done
to the ring buffer.

In record__mmap_read_evlist(), drive this state machine from DATA_PENDING
to EMPTY.

In perf_evlist__mmap_per_evsel(), drive this state machine from NOTREADY
to RUNNING when creating backward mmap.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: He Kuang <hekuang@huawei.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nilay Vaish <nilayvaish@gmail.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1468485287-33422-11-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
54cc54de a0c6f451

+98
+5
tools/perf/builtin-record.c
··· 513 513 if (!maps) 514 514 return 0; 515 515 516 + if (backward && evlist->bkw_mmap_state != BKW_MMAP_DATA_PENDING) 517 + return 0; 518 + 516 519 for (i = 0; i < evlist->nr_mmaps; i++) { 517 520 struct auxtrace_mmap *mm = &maps[i].auxtrace_mmap; 518 521 ··· 541 538 if (bytes_written != rec->bytes_written) 542 539 rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); 543 540 541 + if (backward) 542 + perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY); 544 543 out: 545 544 return rc; 546 545 }
+62
tools/perf/util/evlist.c
··· 15 15 #include "evlist.h" 16 16 #include "evsel.h" 17 17 #include "debug.h" 18 + #include "asm/bug.h" 18 19 #include <unistd.h> 19 20 20 21 #include "parse-events.h" ··· 45 44 perf_evlist__set_maps(evlist, cpus, threads); 46 45 fdarray__init(&evlist->pollfd, 64); 47 46 evlist->workload.pid = -1; 47 + evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; 48 48 } 49 49 50 50 struct perf_evlist *perf_evlist__new(void) ··· 1070 1068 if (!maps) 1071 1069 return -1; 1072 1070 evlist->backward_mmap = maps; 1071 + if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) 1072 + perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); 1073 1073 } 1074 1074 } 1075 1075 ··· 1975 1971 } 1976 1972 1977 1973 return NULL; 1974 + } 1975 + 1976 + void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, 1977 + enum bkw_mmap_state state) 1978 + { 1979 + enum bkw_mmap_state old_state = evlist->bkw_mmap_state; 1980 + enum action { 1981 + NONE, 1982 + PAUSE, 1983 + RESUME, 1984 + } action = NONE; 1985 + 1986 + if (!evlist->backward_mmap) 1987 + return; 1988 + 1989 + switch (old_state) { 1990 + case BKW_MMAP_NOTREADY: { 1991 + if (state != BKW_MMAP_RUNNING) 1992 + goto state_err;; 1993 + break; 1994 + } 1995 + case BKW_MMAP_RUNNING: { 1996 + if (state != BKW_MMAP_DATA_PENDING) 1997 + goto state_err; 1998 + action = PAUSE; 1999 + break; 2000 + } 2001 + case BKW_MMAP_DATA_PENDING: { 2002 + if (state != BKW_MMAP_EMPTY) 2003 + goto state_err; 2004 + break; 2005 + } 2006 + case BKW_MMAP_EMPTY: { 2007 + if (state != BKW_MMAP_RUNNING) 2008 + goto state_err; 2009 + action = RESUME; 2010 + break; 2011 + } 2012 + default: 2013 + WARN_ONCE(1, "Shouldn't get there\n"); 2014 + } 2015 + 2016 + evlist->bkw_mmap_state = state; 2017 + 2018 + switch (action) { 2019 + case PAUSE: 2020 + perf_evlist__pause(evlist); 2021 + break; 2022 + case RESUME: 2023 + perf_evlist__resume(evlist); 2024 + break; 2025 + case NONE: 2026 + default: 2027 + break; 2028 + } 2029 + 2030 + state_err: 2031 + return; 1978 2032 }
+31
tools/perf/util/evlist.h
··· 41 41 return map->mask + 1 + page_size; 42 42 } 43 43 44 + /* 45 + * State machine of bkw_mmap_state: 46 + * 47 + * .________________(forbid)_____________. 48 + * | V 49 + * NOTREADY --(0)--> RUNNING --(1)--> DATA_PENDING --(2)--> EMPTY 50 + * ^ ^ | ^ | 51 + * | |__(forbid)____/ |___(forbid)___/| 52 + * | | 53 + * \_________________(3)_______________/ 54 + * 55 + * NOTREADY : Backward ring buffers are not ready 56 + * RUNNING : Backward ring buffers are recording 57 + * DATA_PENDING : We are required to collect data from backward ring buffers 58 + * EMPTY : We have collected data from backward ring buffers. 59 + * 60 + * (0): Setup backward ring buffer 61 + * (1): Pause ring buffers for reading 62 + * (2): Read from ring buffers 63 + * (3): Resume ring buffers for recording 64 + */ 65 + enum bkw_mmap_state { 66 + BKW_MMAP_NOTREADY, 67 + BKW_MMAP_RUNNING, 68 + BKW_MMAP_DATA_PENDING, 69 + BKW_MMAP_EMPTY, 70 + }; 71 + 44 72 struct perf_evlist { 45 73 struct list_head entries; 46 74 struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; ··· 82 54 int id_pos; 83 55 int is_pos; 84 56 u64 combined_sample_type; 57 + enum bkw_mmap_state bkw_mmap_state; 85 58 struct { 86 59 int cork_fd; 87 60 pid_t pid; ··· 163 134 u64 id); 164 135 165 136 struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); 137 + 138 + void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, enum bkw_mmap_state state); 166 139 167 140 union perf_event *perf_mmap__read_forward(struct perf_mmap *map, bool check_messup); 168 141 union perf_event *perf_mmap__read_backward(struct perf_mmap *map);