Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
f4c6217
Documentation
LICENSES
arch
block
certs
crypto
drivers
fs
include
init
ipc
kernel
lib
mm
net
samples
scripts
security
sound
tools
accounting
arch
bootconfig
bpf
build
cgroup
debugging
edid
firewire
firmware
gpio
hv
iio
include
io_uring
kvm
laptop
leds
lib
memory-model
objtool
pci
pcmcia
perf
Documentation
arch
bench
examples
include
jvmti
pmu-events
python
scripts
tests
trace
ui
util
arm-spe-decoder
bpf_skel
c++
cs-etm-decoder
include
intel-pt-decoder
libunwind
scripting-engines
Build
PERF-VERSION-GEN
affinity.c
affinity.h
annotate.c
annotate.h
archinsn.h
arm-spe.c
arm-spe.h
auxtrace.c
auxtrace.h
block-info.c
block-info.h
block-range.c
block-range.h
bpf-event.c
bpf-event.h
bpf-loader.c
bpf-loader.h
bpf-prologue.c
bpf-prologue.h
bpf_counter.c
bpf_counter.h
bpf_counter_cgroup.c
bpf_map.c
bpf_map.h
branch.c
branch.h
build-id.c
build-id.h
cache.h
cacheline.c
cacheline.h
call-path.c
call-path.h
callchain.c
callchain.h
cap.c
cap.h
cgroup.c
cgroup.h
clockid.c
clockid.h
cloexec.c
cloexec.h
color.c
color.h
color_config.c
comm.c
comm.h
compress.h
config.c
config.h
copyfile.c
copyfile.h
counts.c
counts.h
cpu-set-sched.h
cpumap.c
cpumap.h
cputopo.c
cputopo.h
cs-etm.c
cs-etm.h
data-convert-bt.c
data-convert-json.c
data-convert.h
data.c
data.h
db-export.c
db-export.h
debug.c
debug.h
demangle-java.c
demangle-java.h
demangle-ocaml.c
demangle-ocaml.h
demangle-rust.c
demangle-rust.h
dlfilter.c
dlfilter.h
dso.c
dso.h
dsos.c
dsos.h
dump-insn.c
dump-insn.h
dwarf-aux.c
dwarf-aux.h
dwarf-regs.c
env.c
env.h
event.c
event.h
events_stats.h
evlist-hybrid.c
evlist-hybrid.h
evlist.c
evlist.h
evsel.c
evsel.h
evsel_config.h
evsel_fprintf.c
evsel_fprintf.h
evswitch.c
evswitch.h
expr.c
expr.h
expr.l
expr.y
find-map.c
fncache.c
fncache.h
genelf.c
genelf.h
genelf_debug.c
generate-cmdlist.sh
get_current_dir_name.c
get_current_dir_name.h
hashmap.c
hashmap.h
header.c
header.h
help-unknown-cmd.c
help-unknown-cmd.h
hist.c
hist.h
intel-bts.c
intel-bts.h
intel-pt.c
intel-pt.h
intlist.c
intlist.h
iostat.c
iostat.h
jit.h
jitdump.c
jitdump.h
kvm-stat.h
levenshtein.c
levenshtein.h
llvm-utils.c
llvm-utils.h
lzma.c
machine.c
machine.h
map.c
map.h
map_symbol.h
maps.h
mem-events.c
mem-events.h
mem2node.c
mem2node.h
memswap.c
memswap.h
metricgroup.c
metricgroup.h
mmap.c
mmap.h
namespaces.c
namespaces.h
ordered-events.c
ordered-events.h
parse-branch-options.c
parse-branch-options.h
parse-events-hybrid.c
parse-events-hybrid.h
parse-events.c
parse-events.h
parse-events.l
parse-events.y
parse-regs-options.c
parse-regs-options.h
parse-sublevel-options.c
parse-sublevel-options.h
path.c
path.h
perf-hooks-list.h
perf-hooks.c
perf-hooks.h
perf_api_probe.c
perf_api_probe.h
perf_dlfilter.h
perf_event_attr_fprintf.c
perf_regs.c
perf_regs.h
pfm.c
pfm.h
pmu-hybrid.c
pmu-hybrid.h
pmu.c
pmu.h
pmu.l
pmu.y
print_binary.c
print_binary.h
probe-event.c
probe-event.h
probe-file.c
probe-file.h
probe-finder.c
probe-finder.h
pstack.c
pstack.h
python-ext-sources
python.c
rb_resort.h
rblist.c
rblist.h
record.c
record.h
rlimit.c
rlimit.h
rwsem.c
rwsem.h
s390-cpumcf-kernel.h
s390-cpumsf-kernel.h
s390-cpumsf.c
s390-cpumsf.h
s390-sample-raw.c
sample-raw.c
sample-raw.h
session.c
session.h
setns.c
setup.py
sideband_evlist.c
smt.c
smt.h
sort.c
sort.h
spark.c
spark.h
srccode.c
srccode.h
srcline.c
srcline.h
stat-display.c
stat-shadow.c
stat.c
stat.h
strbuf.c
strbuf.h
stream.c
stream.h
strfilter.c
strfilter.h
string.c
string2.h
strlist.c
strlist.h
svghelper.c
svghelper.h
symbol-elf.c
symbol-minimal.c
symbol.c
symbol.h
symbol_conf.h
symbol_fprintf.c
symsrc.h
synthetic-events.c
synthetic-events.h
syscalltbl.c
syscalltbl.h
target.c
target.h
term.c
term.h
thread-stack.c
thread-stack.h
thread.c
thread.h
thread_map.c
thread_map.h
time-utils.c
time-utils.h
tool.h
top.c
top.h
topdown.c
topdown.h
trace-event-info.c
trace-event-parse.c
trace-event-read.c
trace-event-scripting.c
trace-event.c
trace-event.h
trigger.h
tsc.c
tsc.h
units.c
units.h
unwind-libdw.c
unwind-libdw.h
unwind-libunwind-local.c
unwind-libunwind.c
unwind.h
usage.c
util.c
util.h
values.c
values.h
vdso.c
vdso.h
zlib.c
zstd.c
.gitignore
Build
CREDITS
MANIFEST
Makefile
Makefile.config
Makefile.perf
builtin-annotate.c
builtin-bench.c
builtin-buildid-cache.c
builtin-buildid-list.c
builtin-c2c.c
builtin-config.c
builtin-daemon.c
builtin-data.c
builtin-diff.c
builtin-evlist.c
builtin-ftrace.c
builtin-help.c
builtin-inject.c
builtin-kallsyms.c
builtin-kmem.c
builtin-kvm.c
builtin-list.c
builtin-lock.c
builtin-mem.c
builtin-probe.c
builtin-record.c
builtin-report.c
builtin-sched.c
builtin-script.c
builtin-stat.c
builtin-timechart.c
builtin-top.c
builtin-trace.c
builtin-version.c
builtin.h
check-headers.sh
command-list.txt
design.txt
perf-archive.sh
perf-completion.sh
perf-iostat.sh
perf-read-vdso.c
perf-sys.h
perf-with-kcore.sh
perf.c
perf.h
power
rcu
scripts
spi
testing
thermal
time
tracing
usb
virtio
vm
wmi
Makefile
usr
virt
.clang-format
.cocciconfig
.get_maintainer.ignore
.gitattributes
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
Kconfig
MAINTAINERS
Makefile
README
Breadcrumbs
linux
/
tools
/
perf
/
util
/
mem-events.c
Copy path
Blame
Blame
Latest commit
Kajol Jain
and
Peter Zijlstra
perf: Add comment about current state of PERF_MEM_LVL_* namespace and…
Oct 19, 2021
f4c6217
·
Oct 19, 2021
History
History
608 lines (506 loc) · 12.7 KB
Breadcrumbs
linux
/
tools
/
perf
/
util
/
mem-events.c
Top
File metadata and controls
Code
Blame
608 lines (506 loc) · 12.7 KB
Raw
// SPDX-License-Identifier: GPL-2.0 #include <stddef.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <api/fs/fs.h> #include <linux/kernel.h> #include "map_symbol.h" #include "mem-events.h" #include "debug.h" #include "symbol.h" #include "pmu.h" #include "pmu-hybrid.h" unsigned int perf_mem_events__loads_ldlat = 30; #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"), E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"), E(NULL, NULL, NULL), }; #undef E static char mem_loads_name[100]; static bool mem_loads_name__init; struct perf_mem_event * __weak perf_mem_events__ptr(int i) { if (i >= PERF_MEM_EVENTS__MAX) return NULL; return &perf_mem_events[i]; } char * __weak perf_mem_events__name(int i, char *pmu_name __maybe_unused) { struct perf_mem_event *e = perf_mem_events__ptr(i); if (!e) return NULL; if (i == PERF_MEM_EVENTS__LOAD) { if (!mem_loads_name__init) { mem_loads_name__init = true; scnprintf(mem_loads_name, sizeof(mem_loads_name), e->name, perf_mem_events__loads_ldlat); } return mem_loads_name; } return (char *)e->name; } __weak bool is_mem_loads_aux_event(struct evsel *leader __maybe_unused) { return false; } int perf_mem_events__parse(const char *str) { char *tok, *saveptr = NULL; bool found = false; char *buf; int j; /* We need buffer that we know we can write to. */ buf = malloc(strlen(str) + 1); if (!buf) return -ENOMEM; strcpy(buf, str); tok = strtok_r((char *)buf, ",", &saveptr); while (tok) { for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { struct perf_mem_event *e = perf_mem_events__ptr(j); if (!e->tag) continue; if (strstr(e->tag, tok)) e->record = found = true; } tok = strtok_r(NULL, ",", &saveptr); } free(buf); if (found) return 0; pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str); return -1; } static bool perf_mem_event__supported(const char *mnt, char *sysfs_name) { char path[PATH_MAX]; struct stat st; scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name); return !stat(path, &st); } int perf_mem_events__init(void) { const char *mnt = sysfs__mount(); bool found = false; int j; if (!mnt) return -ENOENT; for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { struct perf_mem_event *e = perf_mem_events__ptr(j); struct perf_pmu *pmu; char sysfs_name[100]; /* * If the event entry isn't valid, skip initialization * and "e->supported" will keep false. */ if (!e->tag) continue; if (!perf_pmu__has_hybrid()) { scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, "cpu"); e->supported = perf_mem_event__supported(mnt, sysfs_name); } else { perf_pmu__for_each_hybrid_pmu(pmu) { scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name); e->supported |= perf_mem_event__supported(mnt, sysfs_name); } } if (e->supported) found = true; } return found ? 0 : -ENOENT; } void perf_mem_events__list(void) { int j; for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { struct perf_mem_event *e = perf_mem_events__ptr(j); fprintf(stderr, "%-13s%-*s%s\n", e->tag ?: "", verbose > 0 ? 25 : 0, verbose > 0 ? perf_mem_events__name(j, NULL) : "", e->supported ? ": available" : ""); } } static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, int idx) { const char *mnt = sysfs__mount(); char sysfs_name[100]; struct perf_pmu *pmu; perf_pmu__for_each_hybrid_pmu(pmu) { scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name); if (!perf_mem_event__supported(mnt, sysfs_name)) { pr_err("failed: event '%s' not supported\n", perf_mem_events__name(idx, pmu->name)); } } } int perf_mem_events__record_args(const char **rec_argv, int *argv_nr, char **rec_tmp, int *tmp_nr) { int i = *argv_nr, k = 0; struct perf_mem_event *e; struct perf_pmu *pmu; char *s; for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) { e = perf_mem_events__ptr(j); if (!e->record) continue; if (!perf_pmu__has_hybrid()) { if (!e->supported) { pr_err("failed: event '%s' not supported\n", perf_mem_events__name(j, NULL)); return -1; } rec_argv[i++] = "-e"; rec_argv[i++] = perf_mem_events__name(j, NULL); } else { if (!e->supported) { perf_mem_events__print_unsupport_hybrid(e, j); return -1; } perf_pmu__for_each_hybrid_pmu(pmu) { rec_argv[i++] = "-e"; s = perf_mem_events__name(j, pmu->name); if (s) { s = strdup(s); if (!s) return -1; rec_argv[i++] = s; rec_tmp[k++] = s; } } } } *argv_nr = i; *tmp_nr = k; return 0; } static const char * const tlb_access[] = { "N/A", "HIT", "MISS", "L1", "L2", "Walker", "Fault", }; int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info) { size_t l = 0, i; u64 m = PERF_MEM_TLB_NA; u64 hit, miss; sz -= 1; /* -1 for null termination */ out[0] = '\0'; if (mem_info) m = mem_info->data_src.mem_dtlb; hit = m & PERF_MEM_TLB_HIT; miss = m & PERF_MEM_TLB_MISS; /* already taken care of */ m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) { if (!(m & 0x1)) continue; if (l) { strcat(out, " or "); l += 4; } l += scnprintf(out + l, sz - l, tlb_access[i]); } if (*out == '\0') l += scnprintf(out, sz - l, "N/A"); if (hit) l += scnprintf(out + l, sz - l, " hit"); if (miss) l += scnprintf(out + l, sz - l, " miss"); return l; } static const char * const mem_lvl[] = { "N/A", "HIT", "MISS", "L1", "LFB", "L2", "L3", "Local RAM", "Remote RAM (1 hop)", "Remote RAM (2 hops)", "Remote Cache (1 hop)", "Remote Cache (2 hops)", "I/O", "Uncached", }; static const char * const mem_lvlnum[] = { [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache", [PERF_MEM_LVLNUM_LFB] = "LFB", [PERF_MEM_LVLNUM_RAM] = "RAM", [PERF_MEM_LVLNUM_PMEM] = "PMEM", [PERF_MEM_LVLNUM_NA] = "N/A", }; int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info) { size_t i, l = 0; u64 m = PERF_MEM_LVL_NA; u64 hit, miss; int printed; if (mem_info) m = mem_info->data_src.mem_lvl; sz -= 1; /* -1 for null termination */ out[0] = '\0'; hit = m & PERF_MEM_LVL_HIT; miss = m & PERF_MEM_LVL_MISS; /* already taken care of */ m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); if (mem_info && mem_info->data_src.mem_remote) { strcat(out, "Remote "); l += 7; } printed = 0; for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) { if (!(m & 0x1)) continue; if (printed++) { strcat(out, " or "); l += 4; } l += scnprintf(out + l, sz - l, mem_lvl[i]); } if (mem_info && mem_info->data_src.mem_lvl_num) { int lvl = mem_info->data_src.mem_lvl_num; if (printed++) { strcat(out, " or "); l += 4; } if (mem_lvlnum[lvl]) l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]); else l += scnprintf(out + l, sz - l, "L%d", lvl); } if (l == 0) l += scnprintf(out + l, sz - l, "N/A"); if (hit) l += scnprintf(out + l, sz - l, " hit"); if (miss) l += scnprintf(out + l, sz - l, " miss"); return l; } static const char * const snoop_access[] = { "N/A", "None", "Hit", "Miss", "HitM", }; int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info) { size_t i, l = 0; u64 m = PERF_MEM_SNOOP_NA; sz -= 1; /* -1 for null termination */ out[0] = '\0'; if (mem_info) m = mem_info->data_src.mem_snoop; for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) { if (!(m & 0x1)) continue; if (l) { strcat(out, " or "); l += 4; } l += scnprintf(out + l, sz - l, snoop_access[i]); } if (mem_info && (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) { if (l) { strcat(out, " or "); l += 4; } l += scnprintf(out + l, sz - l, "Fwd"); } if (*out == '\0') l += scnprintf(out, sz - l, "N/A"); return l; } int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info) { u64 mask = PERF_MEM_LOCK_NA; int l; if (mem_info) mask = mem_info->data_src.mem_lock; if (mask & PERF_MEM_LOCK_NA) l = scnprintf(out, sz, "N/A"); else if (mask & PERF_MEM_LOCK_LOCKED) l = scnprintf(out, sz, "Yes"); else l = scnprintf(out, sz, "No"); return l; } int perf_mem__blk_scnprintf(char *out, size_t sz, struct mem_info *mem_info) { size_t l = 0; u64 mask = PERF_MEM_BLK_NA; sz -= 1; /* -1 for null termination */ out[0] = '\0'; if (mem_info) mask = mem_info->data_src.mem_blk; if (!mask || (mask & PERF_MEM_BLK_NA)) { l += scnprintf(out + l, sz - l, " N/A"); return l; } if (mask & PERF_MEM_BLK_DATA) l += scnprintf(out + l, sz - l, " Data"); if (mask & PERF_MEM_BLK_ADDR) l += scnprintf(out + l, sz - l, " Addr"); return l; } int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info) { int i = 0; i += perf_mem__lvl_scnprintf(out, sz, mem_info); i += scnprintf(out + i, sz - i, "|SNP "); i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info); i += scnprintf(out + i, sz - i, "|TLB "); i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info); i += scnprintf(out + i, sz - i, "|LCK "); i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info); i += scnprintf(out + i, sz - i, "|BLK "); i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info); return i; } int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi) { union perf_mem_data_src *data_src = &mi->data_src; u64 daddr = mi->daddr.addr; u64 op = data_src->mem_op; u64 lvl = data_src->mem_lvl; u64 snoop = data_src->mem_snoop; u64 lock = data_src->mem_lock; u64 blk = data_src->mem_blk; /* * Skylake might report unknown remote level via this * bit, consider it when evaluating remote HITMs. */ bool mrem = data_src->mem_remote; int err = 0; #define HITM_INC(__f) \ do { \ stats->__f++; \ stats->tot_hitm++; \ } while (0) #define P(a, b) PERF_MEM_##a##_##b stats->nr_entries++; if (lock & P(LOCK, LOCKED)) stats->locks++; if (blk & P(BLK, DATA)) stats->blk_data++; if (blk & P(BLK, ADDR)) stats->blk_addr++; if (op & P(OP, LOAD)) { /* load */ stats->load++; if (!daddr) { stats->ld_noadrs++; return -1; } if (lvl & P(LVL, HIT)) { if (lvl & P(LVL, UNC)) stats->ld_uncache++; if (lvl & P(LVL, IO)) stats->ld_io++; if (lvl & P(LVL, LFB)) stats->ld_fbhit++; if (lvl & P(LVL, L1 )) stats->ld_l1hit++; if (lvl & P(LVL, L2 )) stats->ld_l2hit++; if (lvl & P(LVL, L3 )) { if (snoop & P(SNOOP, HITM)) HITM_INC(lcl_hitm); else stats->ld_llchit++; } if (lvl & P(LVL, LOC_RAM)) { stats->lcl_dram++; if (snoop & P(SNOOP, HIT)) stats->ld_shared++; else stats->ld_excl++; } if ((lvl & P(LVL, REM_RAM1)) || (lvl & P(LVL, REM_RAM2)) || mrem) { stats->rmt_dram++; if (snoop & P(SNOOP, HIT)) stats->ld_shared++; else stats->ld_excl++; } } if ((lvl & P(LVL, REM_CCE1)) || (lvl & P(LVL, REM_CCE2)) || mrem) { if (snoop & P(SNOOP, HIT)) stats->rmt_hit++; else if (snoop & P(SNOOP, HITM)) HITM_INC(rmt_hitm); } if ((lvl & P(LVL, MISS))) stats->ld_miss++; } else if (op & P(OP, STORE)) { /* store */ stats->store++; if (!daddr) { stats->st_noadrs++; return -1; } if (lvl & P(LVL, HIT)) { if (lvl & P(LVL, UNC)) stats->st_uncache++; if (lvl & P(LVL, L1 )) stats->st_l1hit++; } if (lvl & P(LVL, MISS)) if (lvl & P(LVL, L1)) stats->st_l1miss++; } else { /* unparsable data_src? */ stats->noparse++; return -1; } if (!mi->daddr.ms.map || !mi->iaddr.ms.map) { stats->nomap++; return -1; } #undef P #undef HITM_INC return err; } void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add) { stats->nr_entries += add->nr_entries; stats->locks += add->locks; stats->store += add->store; stats->st_uncache += add->st_uncache; stats->st_noadrs += add->st_noadrs; stats->st_l1hit += add->st_l1hit; stats->st_l1miss += add->st_l1miss; stats->load += add->load; stats->ld_excl += add->ld_excl; stats->ld_shared += add->ld_shared; stats->ld_uncache += add->ld_uncache; stats->ld_io += add->ld_io; stats->ld_miss += add->ld_miss; stats->ld_noadrs += add->ld_noadrs; stats->ld_fbhit += add->ld_fbhit; stats->ld_l1hit += add->ld_l1hit; stats->ld_l2hit += add->ld_l2hit; stats->ld_llchit += add->ld_llchit; stats->lcl_hitm += add->lcl_hitm; stats->rmt_hitm += add->rmt_hitm; stats->tot_hitm += add->tot_hitm; stats->rmt_hit += add->rmt_hit; stats->lcl_dram += add->lcl_dram; stats->rmt_dram += add->rmt_dram; stats->blk_data += add->blk_data; stats->blk_addr += add->blk_addr; stats->nomap += add->nomap; stats->noparse += add->noparse; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
You can’t perform that action at this time.