Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
7588bada
cloud-kernel
项目概览
openanolis
/
cloud-kernel
大约 1 年 前同步成功
通知
158
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
7588bada
编写于
10月 10, 2011
作者:
I
Ingo Molnar
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'perf/core' of
git://github.com/acmel/linux
into perf/core
上级
d48b0e17
64c6f0c7
变更
35
展开全部
隐藏空白更改
内联
并排
Showing
35 changed file
with
2124 addition
and
804 deletion
+2124
-804
tools/perf/Documentation/perf-annotate.txt
tools/perf/Documentation/perf-annotate.txt
+1
-2
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-report.txt
+16
-1
tools/perf/Documentation/perf-script.txt
tools/perf/Documentation/perf-script.txt
+7
-0
tools/perf/Documentation/perf-top.txt
tools/perf/Documentation/perf-top.txt
+45
-3
tools/perf/Makefile
tools/perf/Makefile
+0
-4
tools/perf/arch/powerpc/Makefile
tools/perf/arch/powerpc/Makefile
+1
-0
tools/perf/arch/powerpc/util/header.c
tools/perf/arch/powerpc/util/header.c
+36
-0
tools/perf/arch/x86/Makefile
tools/perf/arch/x86/Makefile
+1
-0
tools/perf/arch/x86/util/header.c
tools/perf/arch/x86/util/header.c
+59
-0
tools/perf/builtin-annotate.c
tools/perf/builtin-annotate.c
+8
-5
tools/perf/builtin-diff.c
tools/perf/builtin-diff.c
+1
-1
tools/perf/builtin-record.c
tools/perf/builtin-record.c
+15
-0
tools/perf/builtin-report.c
tools/perf/builtin-report.c
+17
-4
tools/perf/builtin-script.c
tools/perf/builtin-script.c
+5
-1
tools/perf/builtin-top.c
tools/perf/builtin-top.c
+267
-170
tools/perf/builtin.h
tools/perf/builtin.h
+0
-1
tools/perf/perf.h
tools/perf/perf.h
+11
-0
tools/perf/util/annotate.h
tools/perf/util/annotate.h
+5
-2
tools/perf/util/evlist.c
tools/perf/util/evlist.c
+6
-0
tools/perf/util/evlist.h
tools/perf/util/evlist.h
+4
-0
tools/perf/util/evsel.c
tools/perf/util/evsel.c
+1
-0
tools/perf/util/header.c
tools/perf/util/header.c
+1114
-31
tools/perf/util/header.h
tools/perf/util/header.h
+27
-2
tools/perf/util/hist.c
tools/perf/util/hist.c
+241
-99
tools/perf/util/hist.h
tools/perf/util/hist.h
+26
-7
tools/perf/util/session.c
tools/perf/util/session.c
+19
-0
tools/perf/util/session.h
tools/perf/util/session.h
+1
-0
tools/perf/util/sort.h
tools/perf/util/sort.h
+1
-0
tools/perf/util/symbol.c
tools/perf/util/symbol.c
+0
-1
tools/perf/util/symbol.h
tools/perf/util/symbol.h
+1
-0
tools/perf/util/top.c
tools/perf/util/top.c
+2
-139
tools/perf/util/top.h
tools/perf/util/top.h
+2
-34
tools/perf/util/ui/browsers/annotate.c
tools/perf/util/ui/browsers/annotate.c
+84
-15
tools/perf/util/ui/browsers/hists.c
tools/perf/util/ui/browsers/hists.c
+100
-46
tools/perf/util/ui/browsers/top.c
tools/perf/util/ui/browsers/top.c
+0
-236
未找到文件。
tools/perf/Documentation/perf-annotate.txt
浏览文件 @
7588bada
...
...
@@ -73,8 +73,7 @@ OPTIONS
CPUs.
--asm-raw::
Show raw instruction encoding of assembly instructions. They
are displayed by default, disable with --no-asm-raw.
Show raw instruction encoding of assembly instructions.
--source::
Interleave source code with assembly code. Enabled by default,
...
...
tools/perf/Documentation/perf-report.txt
浏览文件 @
7588bada
...
...
@@ -137,6 +137,21 @@ OPTIONS
-M::
--disassembler-style=:: Set disassembler style for objdump.
--source::
Interleave source code with assembly code. Enabled by default,
disable with --no-source.
--asm-raw::
Show raw instruction encoding of assembly instructions.
--show-total-period:: Show a column with the sum of periods.
-I::
--show-info::
Display extended information about the perf.data file. This adds
information which may be very large and thus may clutter the display.
It currently includes: cpu and numa topology of the host system.
SEE ALSO
--------
linkperf:perf-stat[1]
linkperf:perf-stat[1]
, linkperf:perf-annotate[1]
tools/perf/Documentation/perf-script.txt
浏览文件 @
7588bada
...
...
@@ -188,6 +188,13 @@ OPTIONS
CPUs are specified with -: 0-2. Default is to report samples on all
CPUs.
-I::
--show-info::
Display extended information about the perf.data file. This adds
information which may be very large and thus may clutter the display.
It currently includes: cpu and numa topology of the host system.
It can only be used with the perf script report mode.
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-script-perl[1],
...
...
tools/perf/Documentation/perf-top.txt
浏览文件 @
7588bada
...
...
@@ -106,6 +106,51 @@ Default is to monitor all CPUS.
--zero::
Zero history across display updates.
-s::
--sort::
Sort by key(s): pid, comm, dso, symbol, parent
-n::
--show-nr-samples::
Show a column with the number of samples.
--show-total-period::
Show a column with the sum of periods.
--dsos::
Only consider symbols in these dsos.
--comms::
Only consider symbols in these comms.
--symbols::
Only consider these symbols.
-M::
--disassembler-style=:: Set disassembler style for objdump.
--source::
Interleave source code with assembly code. Enabled by default,
disable with --no-source.
--asm-raw::
Show raw instruction encoding of assembly instructions.
-G [type,min,order]::
--call-graph::
Display call chains using type, min percent threshold and order.
type can be either:
- flat: single column, linear exposure of call chains.
- graph: use a graph tree, displaying absolute overhead rates.
- fractal: like graph, but displays relative rates. Each branch of
the tree is considered as a new profiled object.
order can be either:
- callee: callee based call graph.
- caller: inverted caller based call graph.
Default: fractal,0.5,callee.
INTERACTIVE PROMPTING KEYS
--------------------------
...
...
@@ -130,9 +175,6 @@ INTERACTIVE PROMPTING KEYS
[S]::
Stop annotation, return to full profile display.
[w]::
Toggle between weighted sum and individual count[E]r profile.
[z]::
Toggle event count zeroing across display updates.
...
...
tools/perf/Makefile
浏览文件 @
7588bada
...
...
@@ -466,7 +466,6 @@ else
LIB_OBJS
+=
$(OUTPUT)
util/ui/browsers/annotate.o
LIB_OBJS
+=
$(OUTPUT)
util/ui/browsers/hists.o
LIB_OBJS
+=
$(OUTPUT)
util/ui/browsers/map.o
LIB_OBJS
+=
$(OUTPUT)
util/ui/browsers/top.o
LIB_OBJS
+=
$(OUTPUT)
util/ui/helpline.o
LIB_OBJS
+=
$(OUTPUT)
util/ui/progress.o
LIB_OBJS
+=
$(OUTPUT)
util/ui/util.o
...
...
@@ -729,9 +728,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
$(OUTPUT)util/ui/browsers/annotate.o
:
util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC)
-o
$@
-c
$(ALL_CFLAGS)
-DENABLE_SLFUTURE_CONST
$<
$(OUTPUT)util/ui/browsers/top.o
:
util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC)
-o
$@
-c
$(ALL_CFLAGS)
-DENABLE_SLFUTURE_CONST
$<
$(OUTPUT)util/ui/browsers/hists.o
:
util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC)
-o
$@
-c
$(ALL_CFLAGS)
-DENABLE_SLFUTURE_CONST
$<
...
...
tools/perf/arch/powerpc/Makefile
浏览文件 @
7588bada
...
...
@@ -2,3 +2,4 @@ ifndef NO_DWARF
PERF_HAVE_DWARF_REGS
:=
1
LIB_OBJS
+=
$(OUTPUT)
arch
/
$(ARCH)
/util/dwarf-regs.o
endif
LIB_OBJS
+=
$(OUTPUT)
arch
/
$(ARCH)
/util/header.o
tools/perf/arch/powerpc/util/header.c
0 → 100644
浏览文件 @
7588bada
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../util/header.h"
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
#define mfspr(rn) ({unsigned long rval; \
asm volatile("mfspr %0," __stringify(rn) \
: "=r" (rval)); rval; })
#define SPRN_PVR 0x11F
/* Processor Version Register */
#define PVR_VER(pvr) (((pvr) >> 16) & 0xFFFF)
/* Version field */
#define PVR_REV(pvr) (((pvr) >> 0) & 0xFFFF)
/* Revison field */
int
get_cpuid
(
char
*
buffer
,
size_t
sz
)
{
unsigned
long
pvr
;
int
nb
;
pvr
=
mfspr
(
SPRN_PVR
);
nb
=
snprintf
(
buffer
,
sz
,
"%lu,%lu$"
,
PVR_VER
(
pvr
),
PVR_REV
(
pvr
));
/* look for end marker to ensure the entire data fit */
if
(
strchr
(
buffer
,
'$'
))
{
buffer
[
nb
-
1
]
=
'\0'
;
return
0
;
}
return
-
1
;
}
tools/perf/arch/x86/Makefile
浏览文件 @
7588bada
...
...
@@ -2,3 +2,4 @@ ifndef NO_DWARF
PERF_HAVE_DWARF_REGS
:=
1
LIB_OBJS
+=
$(OUTPUT)
arch
/
$(ARCH)
/util/dwarf-regs.o
endif
LIB_OBJS
+=
$(OUTPUT)
arch
/
$(ARCH)
/util/header.o
tools/perf/arch/x86/util/header.c
0 → 100644
浏览文件 @
7588bada
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../util/header.h"
static
inline
void
cpuid
(
unsigned
int
op
,
unsigned
int
*
a
,
unsigned
int
*
b
,
unsigned
int
*
c
,
unsigned
int
*
d
)
{
__asm__
__volatile__
(
".byte 0x53
\n\t
cpuid
\n\t
"
"movl %%ebx, %%esi
\n\t
.byte 0x5b"
:
"=a"
(
*
a
),
"=S"
(
*
b
),
"=c"
(
*
c
),
"=d"
(
*
d
)
:
"a"
(
op
));
}
int
get_cpuid
(
char
*
buffer
,
size_t
sz
)
{
unsigned
int
a
,
b
,
c
,
d
,
lvl
;
int
family
=
-
1
,
model
=
-
1
,
step
=
-
1
;
int
nb
;
char
vendor
[
16
];
cpuid
(
0
,
&
lvl
,
&
b
,
&
c
,
&
d
);
strncpy
(
&
vendor
[
0
],
(
char
*
)(
&
b
),
4
);
strncpy
(
&
vendor
[
4
],
(
char
*
)(
&
d
),
4
);
strncpy
(
&
vendor
[
8
],
(
char
*
)(
&
c
),
4
);
vendor
[
12
]
=
'\0'
;
if
(
lvl
>=
1
)
{
cpuid
(
1
,
&
a
,
&
b
,
&
c
,
&
d
);
family
=
(
a
>>
8
)
&
0xf
;
/* bits 11 - 8 */
model
=
(
a
>>
4
)
&
0xf
;
/* Bits 7 - 4 */
step
=
a
&
0xf
;
/* extended family */
if
(
family
==
0xf
)
family
+=
(
a
>>
20
)
&
0xff
;
/* extended model */
if
(
family
>=
0x6
)
model
+=
((
a
>>
16
)
&
0xf
)
<<
4
;
}
nb
=
snprintf
(
buffer
,
sz
,
"%s,%u,%u,%u$"
,
vendor
,
family
,
model
,
step
);
/* look for end marker to ensure the entire data fit */
if
(
strchr
(
buffer
,
'$'
))
{
buffer
[
nb
-
1
]
=
'\0'
;
return
0
;
}
return
-
1
;
}
tools/perf/builtin-annotate.c
浏览文件 @
7588bada
...
...
@@ -114,7 +114,8 @@ static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
print_line
,
full_paths
,
0
,
0
);
}
static
void
hists__find_annotations
(
struct
hists
*
self
,
int
evidx
)
static
void
hists__find_annotations
(
struct
hists
*
self
,
int
evidx
,
int
nr_events
)
{
struct
rb_node
*
nd
=
rb_first
(
&
self
->
entries
),
*
next
;
int
key
=
KEY_RIGHT
;
...
...
@@ -137,7 +138,8 @@ static void hists__find_annotations(struct hists *self, int evidx)
}
if
(
use_browser
>
0
)
{
key
=
hist_entry__tui_annotate
(
he
,
evidx
);
key
=
hist_entry__tui_annotate
(
he
,
evidx
,
nr_events
,
NULL
,
NULL
,
0
);
switch
(
key
)
{
case
KEY_RIGHT
:
next
=
rb_next
(
nd
);
...
...
@@ -215,7 +217,8 @@ static int __cmd_annotate(void)
total_nr_samples
+=
nr_samples
;
hists__collapse_resort
(
hists
);
hists__output_resort
(
hists
);
hists__find_annotations
(
hists
,
pos
->
idx
);
hists__find_annotations
(
hists
,
pos
->
idx
,
session
->
evlist
->
nr_entries
);
}
}
...
...
@@ -269,9 +272,9 @@ static const struct option options[] = {
OPT_STRING
(
'c'
,
"cpu"
,
&
cpu_list
,
"cpu"
,
"list of cpus to profile"
),
OPT_STRING
(
0
,
"symfs"
,
&
symbol_conf
.
symfs
,
"directory"
,
"Look for files with symbols relative to this directory"
),
OPT_BOOLEAN
(
'0'
,
"source"
,
&
symbol_conf
.
annotate_src
,
OPT_BOOLEAN
(
0
,
"source"
,
&
symbol_conf
.
annotate_src
,
"Interleave source code with assembly code (default)"
),
OPT_BOOLEAN
(
'0'
,
"asm-raw"
,
&
symbol_conf
.
annotate_asm_raw
,
OPT_BOOLEAN
(
0
,
"asm-raw"
,
&
symbol_conf
.
annotate_asm_raw
,
"Display raw encoding of assembly instructions (default)"
),
OPT_STRING
(
'M'
,
"disassembler-style"
,
&
disassembler_style
,
"disassembler style"
,
"Specify disassembler style (e.g. -M intel for intel syntax)"
),
...
...
tools/perf/builtin-diff.c
浏览文件 @
7588bada
...
...
@@ -162,7 +162,7 @@ static int __cmd_diff(void)
hists__match
(
&
session
[
0
]
->
hists
,
&
session
[
1
]
->
hists
);
hists__fprintf
(
&
session
[
1
]
->
hists
,
&
session
[
0
]
->
hists
,
show_displacement
,
stdout
);
show_displacement
,
true
,
0
,
0
,
stdout
);
out_delete:
for
(
i
=
0
;
i
<
2
;
++
i
)
perf_session__delete
(
session
[
i
]);
...
...
tools/perf/builtin-record.c
浏览文件 @
7588bada
...
...
@@ -529,6 +529,19 @@ static int __cmd_record(int argc, const char **argv)
if
(
have_tracepoints
(
&
evsel_list
->
entries
))
perf_header__set_feat
(
&
session
->
header
,
HEADER_TRACE_INFO
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_HOSTNAME
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_OSRELEASE
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_ARCH
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_CPUDESC
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_NRCPUS
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_EVENT_DESC
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_CMDLINE
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_VERSION
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_CPU_TOPOLOGY
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_TOTAL_MEM
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_NUMA_TOPOLOGY
);
perf_header__set_feat
(
&
session
->
header
,
HEADER_CPUID
);
/* 512 kiB: default amount of unprivileged mlocked memory */
if
(
mmap_pages
==
UINT_MAX
)
mmap_pages
=
(
512
*
1024
)
/
page_size
;
...
...
@@ -800,6 +813,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
int
err
=
-
ENOMEM
;
struct
perf_evsel
*
pos
;
perf_header__set_cmdline
(
argc
,
argv
);
evsel_list
=
perf_evlist__new
(
NULL
,
NULL
);
if
(
evsel_list
==
NULL
)
return
-
ENOMEM
;
...
...
tools/perf/builtin-report.c
浏览文件 @
7588bada
...
...
@@ -40,6 +40,7 @@ static char const *input_name = "perf.data";
static
bool
force
,
use_tui
,
use_stdio
;
static
bool
hide_unresolved
;
static
bool
dont_use_callchains
;
static
bool
show_full_info
;
static
bool
show_threads
;
static
struct
perf_read_values
show_threads_values
;
...
...
@@ -232,7 +233,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
const
char
*
evname
=
event_name
(
pos
);
hists__fprintf_nr_sample_events
(
hists
,
evname
,
stdout
);
hists__fprintf
(
hists
,
NULL
,
false
,
stdout
);
hists__fprintf
(
hists
,
NULL
,
false
,
true
,
0
,
0
,
stdout
);
fprintf
(
stdout
,
"
\n\n
"
);
}
...
...
@@ -273,6 +274,9 @@ static int __cmd_report(void)
goto
out_delete
;
}
if
(
use_browser
<=
0
)
perf_session__fprintf_info
(
session
,
stdout
,
show_full_info
);
if
(
show_threads
)
perf_read_values_init
(
&
show_threads_values
);
...
...
@@ -327,9 +331,10 @@ static int __cmd_report(void)
goto
out_delete
;
}
if
(
use_browser
>
0
)
perf_evlist__tui_browse_hists
(
session
->
evlist
,
help
);
else
if
(
use_browser
>
0
)
{
perf_evlist__tui_browse_hists
(
session
->
evlist
,
help
,
NULL
,
NULL
,
0
);
}
else
perf_evlist__tty_browse_hists
(
session
->
evlist
,
help
);
out_delete:
...
...
@@ -484,8 +489,16 @@ static const struct option options[] = {
OPT_STRING
(
0
,
"symfs"
,
&
symbol_conf
.
symfs
,
"directory"
,
"Look for files with symbols relative to this directory"
),
OPT_STRING
(
'c'
,
"cpu"
,
&
cpu_list
,
"cpu"
,
"list of cpus to profile"
),
OPT_BOOLEAN
(
'I'
,
"show-info"
,
&
show_full_info
,
"Display extended information about perf.data file"
),
OPT_BOOLEAN
(
0
,
"source"
,
&
symbol_conf
.
annotate_src
,
"Interleave source code with assembly code (default)"
),
OPT_BOOLEAN
(
0
,
"asm-raw"
,
&
symbol_conf
.
annotate_asm_raw
,
"Display raw encoding of assembly instructions (default)"
),
OPT_STRING
(
'M'
,
"disassembler-style"
,
&
disassembler_style
,
"disassembler style"
,
"Specify disassembler style (e.g. -M intel for intel syntax)"
),
OPT_BOOLEAN
(
0
,
"show-total-period"
,
&
symbol_conf
.
show_total_period
,
"Show a column with the sum of periods"
),
OPT_END
()
};
...
...
tools/perf/builtin-script.c
浏览文件 @
7588bada
...
...
@@ -22,6 +22,7 @@ static u64 last_timestamp;
static
u64
nr_unordered
;
extern
const
struct
option
record_options
[];
static
bool
no_callchain
;
static
bool
show_full_info
;
static
const
char
*
cpu_list
;
static
DECLARE_BITMAP
(
cpu_bitmap
,
MAX_NR_CPUS
);
...
...
@@ -1083,7 +1084,8 @@ static const struct option options[] = {
"comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr"
,
parse_output_fields
),
OPT_STRING
(
'c'
,
"cpu"
,
&
cpu_list
,
"cpu"
,
"list of cpus to profile"
),
OPT_BOOLEAN
(
'I'
,
"show-info"
,
&
show_full_info
,
"display extended information from perf.data file"
),
OPT_END
()
};
...
...
@@ -1268,6 +1270,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
return
-
1
;
}
perf_session__fprintf_info
(
session
,
stdout
,
show_full_info
);
if
(
!
no_callchain
)
symbol_conf
.
use_callchain
=
true
;
else
...
...
tools/perf/builtin-top.c
浏览文件 @
7588bada
此差异已折叠。
点击以展开。
tools/perf/builtin.h
浏览文件 @
7588bada
...
...
@@ -4,7 +4,6 @@
#include "util/util.h"
#include "util/strbuf.h"
extern
const
char
perf_version_string
[];
extern
const
char
perf_usage_string
[];
extern
const
char
perf_more_info_string
[];
...
...
tools/perf/perf.h
浏览文件 @
7588bada
...
...
@@ -9,18 +9,21 @@ void get_term_dimensions(struct winsize *ws);
#include "../../arch/x86/include/asm/unistd.h"
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
#endif
#if defined(__x86_64__)
#include "../../arch/x86/include/asm/unistd.h"
#define rmb() asm volatile("lfence" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
#endif
#ifdef __powerpc__
#include "../../arch/powerpc/include/asm/unistd.h"
#define rmb() asm volatile ("sync" ::: "memory")
#define cpu_relax() asm volatile ("" ::: "memory");
#define CPUINFO_PROC "cpu"
#endif
#ifdef __s390__
...
...
@@ -37,30 +40,35 @@ void get_term_dimensions(struct winsize *ws);
# define rmb() asm volatile("" ::: "memory")
#endif
#define cpu_relax() asm volatile("" ::: "memory")
#define CPUINFO_PROC "cpu type"
#endif
#ifdef __hppa__
#include "../../arch/parisc/include/asm/unistd.h"
#define rmb() asm volatile("" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory");
#define CPUINFO_PROC "cpu"
#endif
#ifdef __sparc__
#include "../../arch/sparc/include/asm/unistd.h"
#define rmb() asm volatile("":::"memory")
#define cpu_relax() asm volatile("":::"memory")
#define CPUINFO_PROC "cpu"
#endif
#ifdef __alpha__
#include "../../arch/alpha/include/asm/unistd.h"
#define rmb() asm volatile("mb" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory")
#define CPUINFO_PROC "cpu model"
#endif
#ifdef __ia64__
#include "../../arch/ia64/include/asm/unistd.h"
#define rmb() asm volatile ("mf" ::: "memory")
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
#define CPUINFO_PROC "model name"
#endif
#ifdef __arm__
...
...
@@ -71,6 +79,7 @@ void get_term_dimensions(struct winsize *ws);
*/
#define rmb() ((void(*)(void))0xffff0fa0)()
#define cpu_relax() asm volatile("":::"memory")
#define CPUINFO_PROC "Processor"
#endif
#ifdef __mips__
...
...
@@ -83,6 +92,7 @@ void get_term_dimensions(struct winsize *ws);
:
/* no input */
\
: "memory")
#define cpu_relax() asm volatile("" ::: "memory")
#define CPUINFO_PROC "cpu model"
#endif
#include <time.h>
...
...
@@ -171,5 +181,6 @@ struct ip_callchain {
};
extern
bool
perf_host
,
perf_guest
;
extern
const
char
perf_version_string
[];
#endif
tools/perf/util/annotate.h
浏览文件 @
7588bada
...
...
@@ -91,13 +91,16 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
#ifdef NO_NEWT_SUPPORT
static
inline
int
symbol__tui_annotate
(
struct
symbol
*
sym
__used
,
struct
map
*
map
__used
,
int
evidx
__used
,
int
refresh
__used
)
int
evidx
__used
,
void
(
*
timer
)(
void
*
arg
)
__used
,
void
*
arg
__used
,
int
delay_secs
__used
)
{
return
0
;
}
#else
int
symbol__tui_annotate
(
struct
symbol
*
sym
,
struct
map
*
map
,
int
evidx
,
int
refresh
);
int
nr_events
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
);
#endif
extern
const
char
*
disassembler_style
;
...
...
tools/perf/util/evlist.c
浏览文件 @
7588bada
...
...
@@ -533,3 +533,9 @@ bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
first
=
list_entry
(
evlist
->
entries
.
next
,
struct
perf_evsel
,
node
);
return
first
->
attr
.
sample_id_all
;
}
void
perf_evlist__set_selected
(
struct
perf_evlist
*
evlist
,
struct
perf_evsel
*
evsel
)
{
evlist
->
selected
=
evsel
;
}
tools/perf/util/evlist.h
浏览文件 @
7588bada
...
...
@@ -25,6 +25,7 @@ struct perf_evlist {
struct
pollfd
*
pollfd
;
struct
thread_map
*
threads
;
struct
cpu_map
*
cpus
;
struct
perf_evsel
*
selected
;
};
struct
perf_evsel
;
...
...
@@ -56,6 +57,9 @@ void perf_evlist__munmap(struct perf_evlist *evlist);
void
perf_evlist__disable
(
struct
perf_evlist
*
evlist
);
void
perf_evlist__enable
(
struct
perf_evlist
*
evlist
);
void
perf_evlist__set_selected
(
struct
perf_evlist
*
evlist
,
struct
perf_evsel
*
evsel
);
static
inline
void
perf_evlist__set_maps
(
struct
perf_evlist
*
evlist
,
struct
cpu_map
*
cpus
,
struct
thread_map
*
threads
)
...
...
tools/perf/util/evsel.c
浏览文件 @
7588bada
...
...
@@ -39,6 +39,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
evsel
->
idx
=
idx
;
evsel
->
attr
=
*
attr
;
INIT_LIST_HEAD
(
&
evsel
->
node
);
hists__init
(
&
evsel
->
hists
);
}
struct
perf_evsel
*
perf_evsel__new
(
struct
perf_event_attr
*
attr
,
int
idx
)
...
...
tools/perf/util/header.c
浏览文件 @
7588bada
此差异已折叠。
点击以展开。
tools/perf/util/header.h
浏览文件 @
7588bada
...
...
@@ -12,6 +12,20 @@
enum
{
HEADER_TRACE_INFO
=
1
,
HEADER_BUILD_ID
,
HEADER_HOSTNAME
,
HEADER_OSRELEASE
,
HEADER_VERSION
,
HEADER_ARCH
,
HEADER_NRCPUS
,
HEADER_CPUDESC
,
HEADER_CPUID
,
HEADER_TOTAL_MEM
,
HEADER_CMDLINE
,
HEADER_EVENT_DESC
,
HEADER_CPU_TOPOLOGY
,
HEADER_NUMA_TOPOLOGY
,
HEADER_LAST_FEATURE
,
};
...
...
@@ -68,10 +82,15 @@ void perf_header__set_feat(struct perf_header *header, int feat);
void
perf_header__clear_feat
(
struct
perf_header
*
header
,
int
feat
);
bool
perf_header__has_feat
(
const
struct
perf_header
*
header
,
int
feat
);
int
perf_header__set_cmdline
(
int
argc
,
const
char
**
argv
);
int
perf_header__process_sections
(
struct
perf_header
*
header
,
int
fd
,
void
*
data
,
int
(
*
process
)(
struct
perf_file_section
*
section
,
struct
perf_header
*
ph
,
int
feat
,
int
fd
));
struct
perf_header
*
ph
,
int
feat
,
int
fd
,
void
*
data
));
int
perf_header__fprintf_info
(
struct
perf_session
*
s
,
FILE
*
fp
,
bool
full
);
int
build_id_cache__add_s
(
const
char
*
sbuild_id
,
const
char
*
debugdir
,
const
char
*
name
,
bool
is_kallsyms
);
...
...
@@ -104,4 +123,10 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc,
struct
perf_session
*
session
);
int
perf_event__process_build_id
(
union
perf_event
*
event
,
struct
perf_session
*
session
);
/*
* arch specific callback
*/
int
get_cpuid
(
char
*
buffer
,
size_t
sz
);
#endif
/* __PERF_HEADER_H */
tools/perf/util/hist.c
浏览文件 @
7588bada
...
...
@@ -18,56 +18,56 @@ struct callchain_param callchain_param = {
.
order
=
ORDER_CALLEE
};
u16
hists__col_len
(
struct
hists
*
self
,
enum
hist_column
col
)
u16
hists__col_len
(
struct
hists
*
hists
,
enum
hist_column
col
)
{
return
self
->
col_len
[
col
];
return
hists
->
col_len
[
col
];
}
void
hists__set_col_len
(
struct
hists
*
self
,
enum
hist_column
col
,
u16
len
)
void
hists__set_col_len
(
struct
hists
*
hists
,
enum
hist_column
col
,
u16
len
)
{
self
->
col_len
[
col
]
=
len
;
hists
->
col_len
[
col
]
=
len
;
}
bool
hists__new_col_len
(
struct
hists
*
self
,
enum
hist_column
col
,
u16
len
)
bool
hists__new_col_len
(
struct
hists
*
hists
,
enum
hist_column
col
,
u16
len
)
{
if
(
len
>
hists__col_len
(
self
,
col
))
{
hists__set_col_len
(
self
,
col
,
len
);
if
(
len
>
hists__col_len
(
hists
,
col
))
{
hists__set_col_len
(
hists
,
col
,
len
);
return
true
;
}
return
false
;
}
static
void
hists__reset_col_len
(
struct
hists
*
self
)
static
void
hists__reset_col_len
(
struct
hists
*
hists
)
{
enum
hist_column
col
;
for
(
col
=
0
;
col
<
HISTC_NR_COLS
;
++
col
)
hists__set_col_len
(
self
,
col
,
0
);
hists__set_col_len
(
hists
,
col
,
0
);
}
static
void
hists__calc_col_len
(
struct
hists
*
self
,
struct
hist_entry
*
h
)
static
void
hists__calc_col_len
(
struct
hists
*
hists
,
struct
hist_entry
*
h
)
{
u16
len
;
if
(
h
->
ms
.
sym
)
hists__new_col_len
(
self
,
HISTC_SYMBOL
,
h
->
ms
.
sym
->
namelen
);
hists__new_col_len
(
hists
,
HISTC_SYMBOL
,
h
->
ms
.
sym
->
namelen
);
else
{
const
unsigned
int
unresolved_col_width
=
BITS_PER_LONG
/
4
;
if
(
hists__col_len
(
self
,
HISTC_DSO
)
<
unresolved_col_width
&&
if
(
hists__col_len
(
hists
,
HISTC_DSO
)
<
unresolved_col_width
&&
!
symbol_conf
.
col_width_list_str
&&
!
symbol_conf
.
field_sep
&&
!
symbol_conf
.
dso_list
)
hists__set_col_len
(
self
,
HISTC_DSO
,
hists__set_col_len
(
hists
,
HISTC_DSO
,
unresolved_col_width
);
}
len
=
thread__comm_len
(
h
->
thread
);
if
(
hists__new_col_len
(
self
,
HISTC_COMM
,
len
))
hists__set_col_len
(
self
,
HISTC_THREAD
,
len
+
6
);
if
(
hists__new_col_len
(
hists
,
HISTC_COMM
,
len
))
hists__set_col_len
(
hists
,
HISTC_THREAD
,
len
+
6
);
if
(
h
->
ms
.
map
)
{
len
=
dso__name_len
(
h
->
ms
.
map
->
dso
);
hists__new_col_len
(
self
,
HISTC_DSO
,
len
);
hists__new_col_len
(
hists
,
HISTC_DSO
,
len
);
}
}
...
...
@@ -92,6 +92,41 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
}
}
static
void
hist_entry__decay
(
struct
hist_entry
*
he
)
{
he
->
period
=
(
he
->
period
*
7
)
/
8
;
he
->
nr_events
=
(
he
->
nr_events
*
7
)
/
8
;
}
static
bool
hists__decay_entry
(
struct
hists
*
hists
,
struct
hist_entry
*
he
)
{
hists
->
stats
.
total_period
-=
he
->
period
;
hist_entry__decay
(
he
);
hists
->
stats
.
total_period
+=
he
->
period
;
return
he
->
period
==
0
;
}
void
hists__decay_entries
(
struct
hists
*
hists
)
{
struct
rb_node
*
next
=
rb_first
(
&
hists
->
entries
);
struct
hist_entry
*
n
;
while
(
next
)
{
n
=
rb_entry
(
next
,
struct
hist_entry
,
rb_node
);
next
=
rb_next
(
&
n
->
rb_node
);
if
(
hists__decay_entry
(
hists
,
n
))
{
rb_erase
(
&
n
->
rb_node
,
&
hists
->
entries
);
if
(
sort__need_collapse
)
rb_erase
(
&
n
->
rb_node_in
,
&
hists
->
entries_collapsed
);
hist_entry__free
(
n
);
--
hists
->
nr_entries
;
}
}
}
/*
* histogram, sorted on item, collects periods
*/
...
...
@@ -113,11 +148,12 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
return
self
;
}
static
void
hists__inc_nr_entries
(
struct
hists
*
self
,
struct
hist_entry
*
h
)
static
void
hists__inc_nr_entries
(
struct
hists
*
hists
,
struct
hist_entry
*
h
)
{
if
(
!
h
->
filtered
)
{
hists__calc_col_len
(
self
,
h
);
++
self
->
nr_entries
;
hists__calc_col_len
(
hists
,
h
);
++
hists
->
nr_entries
;
hists
->
stats
.
total_period
+=
h
->
period
;
}
}
...
...
@@ -128,11 +164,11 @@ static u8 symbol__parent_filter(const struct symbol *parent)
return
0
;
}
struct
hist_entry
*
__hists__add_entry
(
struct
hists
*
self
,
struct
hist_entry
*
__hists__add_entry
(
struct
hists
*
hists
,
struct
addr_location
*
al
,
struct
symbol
*
sym_parent
,
u64
period
)
{
struct
rb_node
**
p
=
&
self
->
entries
.
rb_node
;
struct
rb_node
**
p
;
struct
rb_node
*
parent
=
NULL
;
struct
hist_entry
*
he
;
struct
hist_entry
entry
=
{
...
...
@@ -150,9 +186,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
};
int
cmp
;
pthread_mutex_lock
(
&
hists
->
lock
);
p
=
&
hists
->
entries_in
->
rb_node
;
while
(
*
p
!=
NULL
)
{
parent
=
*
p
;
he
=
rb_entry
(
parent
,
struct
hist_entry
,
rb_node
);
he
=
rb_entry
(
parent
,
struct
hist_entry
,
rb_node
_in
);
cmp
=
hist_entry__cmp
(
&
entry
,
he
);
...
...
@@ -170,12 +210,14 @@ struct hist_entry *__hists__add_entry(struct hists *self,
he
=
hist_entry__new
(
&
entry
);
if
(
!
he
)
return
NULL
;
rb_link_node
(
&
he
->
rb_node
,
parent
,
p
);
rb_
insert_color
(
&
he
->
rb_node
,
&
self
->
entries
);
hists__inc_nr_entries
(
self
,
he
);
goto
out_unlock
;
rb_
link_node
(
&
he
->
rb_node_in
,
parent
,
p
);
rb_insert_color
(
&
he
->
rb_node_in
,
hists
->
entries_in
);
out:
hist_entry__add_cpumode_period
(
he
,
al
->
cpumode
,
period
);
out_unlock:
pthread_mutex_unlock
(
&
hists
->
lock
);
return
he
;
}
...
...
@@ -222,7 +264,7 @@ void hist_entry__free(struct hist_entry *he)
* collapse the histogram
*/
static
bool
hists__collapse_insert_entry
(
struct
hists
*
self
,
static
bool
hists__collapse_insert_entry
(
struct
hists
*
hists
,
struct
rb_root
*
root
,
struct
hist_entry
*
he
)
{
...
...
@@ -233,15 +275,16 @@ static bool hists__collapse_insert_entry(struct hists *self,
while
(
*
p
!=
NULL
)
{
parent
=
*
p
;
iter
=
rb_entry
(
parent
,
struct
hist_entry
,
rb_node
);
iter
=
rb_entry
(
parent
,
struct
hist_entry
,
rb_node
_in
);
cmp
=
hist_entry__collapse
(
iter
,
he
);
if
(
!
cmp
)
{
iter
->
period
+=
he
->
period
;
iter
->
nr_events
+=
he
->
nr_events
;
if
(
symbol_conf
.
use_callchain
)
{
callchain_cursor_reset
(
&
self
->
callchain_cursor
);
callchain_merge
(
&
self
->
callchain_cursor
,
iter
->
callchain
,
callchain_cursor_reset
(
&
hists
->
callchain_cursor
);
callchain_merge
(
&
hists
->
callchain_cursor
,
iter
->
callchain
,
he
->
callchain
);
}
hist_entry__free
(
he
);
...
...
@@ -254,35 +297,57 @@ static bool hists__collapse_insert_entry(struct hists *self,
p
=
&
(
*
p
)
->
rb_right
;
}
rb_link_node
(
&
he
->
rb_node
,
parent
,
p
);
rb_insert_color
(
&
he
->
rb_node
,
root
);
rb_link_node
(
&
he
->
rb_node
_in
,
parent
,
p
);
rb_insert_color
(
&
he
->
rb_node
_in
,
root
);
return
true
;
}
void
hists__collapse_resort
(
struct
hists
*
self
)
static
struct
rb_root
*
hists__get_rotate_entries_in
(
struct
hists
*
hists
)
{
struct
rb_root
*
root
;
pthread_mutex_lock
(
&
hists
->
lock
);
root
=
hists
->
entries_in
;
if
(
++
hists
->
entries_in
>
&
hists
->
entries_in_array
[
1
])
hists
->
entries_in
=
&
hists
->
entries_in_array
[
0
];
pthread_mutex_unlock
(
&
hists
->
lock
);
return
root
;
}
static
void
__hists__collapse_resort
(
struct
hists
*
hists
,
bool
threaded
)
{
struct
rb_root
tmp
;
struct
rb_root
*
root
;
struct
rb_node
*
next
;
struct
hist_entry
*
n
;
if
(
!
sort__need_collapse
)
if
(
!
sort__need_collapse
&&
!
threaded
)
return
;
tmp
=
RB_ROOT
;
next
=
rb_first
(
&
self
->
entries
);
self
->
nr_entries
=
0
;
hists__reset_col_len
(
self
);
root
=
hists__get_rotate_entries_in
(
hists
);
next
=
rb_first
(
root
);
hists
->
stats
.
total_period
=
0
;
while
(
next
)
{
n
=
rb_entry
(
next
,
struct
hist_entry
,
rb_node
);
next
=
rb_next
(
&
n
->
rb_node
);
n
=
rb_entry
(
next
,
struct
hist_entry
,
rb_node
_in
);
next
=
rb_next
(
&
n
->
rb_node
_in
);
rb_erase
(
&
n
->
rb_node
,
&
self
->
entries
);
if
(
hists__collapse_insert_entry
(
self
,
&
tmp
,
n
))
hists__inc_nr_entries
(
self
,
n
);
rb_erase
(
&
n
->
rb_node
_in
,
root
);
if
(
hists__collapse_insert_entry
(
hists
,
&
hists
->
entries_collapsed
,
n
))
hists__inc_nr_entries
(
hists
,
n
);
}
}
self
->
entries
=
tmp
;
void
hists__collapse_resort
(
struct
hists
*
hists
)
{
return
__hists__collapse_resort
(
hists
,
false
);
}
void
hists__collapse_resort_threaded
(
struct
hists
*
hists
)
{
return
__hists__collapse_resort
(
hists
,
true
);
}
/*
...
...
@@ -315,31 +380,43 @@ static void __hists__insert_output_entry(struct rb_root *entries,
rb_insert_color
(
&
he
->
rb_node
,
entries
);
}
void
hists__output_resort
(
struct
hists
*
self
)
static
void
__hists__output_resort
(
struct
hists
*
hists
,
bool
threaded
)
{
struct
rb_root
tmp
;
struct
rb_root
*
root
;
struct
rb_node
*
next
;
struct
hist_entry
*
n
;
u64
min_callchain_hits
;
min_callchain_hits
=
self
->
stats
.
total_period
*
(
callchain_param
.
min_percent
/
100
);
min_callchain_hits
=
hists
->
stats
.
total_period
*
(
callchain_param
.
min_percent
/
100
);
if
(
sort__need_collapse
||
threaded
)
root
=
&
hists
->
entries_collapsed
;
else
root
=
hists
->
entries_in
;
tmp
=
RB_ROOT
;
next
=
rb_first
(
&
self
->
entries
)
;
next
=
rb_first
(
root
)
;
hists
->
entries
=
RB_ROOT
;
self
->
nr_entries
=
0
;
hists__reset_col_len
(
self
);
hists
->
nr_entries
=
0
;
hists__reset_col_len
(
hists
);
while
(
next
)
{
n
=
rb_entry
(
next
,
struct
hist_entry
,
rb_node
);
next
=
rb_next
(
&
n
->
rb_node
);
n
=
rb_entry
(
next
,
struct
hist_entry
,
rb_node
_in
);
next
=
rb_next
(
&
n
->
rb_node
_in
);
rb_erase
(
&
n
->
rb_node
,
&
self
->
entries
);
__hists__insert_output_entry
(
&
tmp
,
n
,
min_callchain_hits
);
hists__inc_nr_entries
(
self
,
n
);
__hists__insert_output_entry
(
&
hists
->
entries
,
n
,
min_callchain_hits
);
hists__inc_nr_entries
(
hists
,
n
);
}
}
void
hists__output_resort
(
struct
hists
*
hists
)
{
return
__hists__output_resort
(
hists
,
false
);
}
self
->
entries
=
tmp
;
void
hists__output_resort_threaded
(
struct
hists
*
hists
)
{
return
__hists__output_resort
(
hists
,
true
);
}
static
size_t
callchain__fprintf_left_margin
(
FILE
*
fp
,
int
left_margin
)
...
...
@@ -594,6 +671,21 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
return
ret
;
}
void
hists__output_recalc_col_len
(
struct
hists
*
hists
,
int
max_rows
)
{
struct
rb_node
*
next
=
rb_first
(
&
hists
->
entries
);
struct
hist_entry
*
n
;
int
row
=
0
;
hists__reset_col_len
(
hists
);
while
(
next
&&
row
++
<
max_rows
)
{
n
=
rb_entry
(
next
,
struct
hist_entry
,
rb_node
);
hists__calc_col_len
(
hists
,
n
);
next
=
rb_next
(
&
n
->
rb_node
);
}
}
int
hist_entry__snprintf
(
struct
hist_entry
*
self
,
char
*
s
,
size_t
size
,
struct
hists
*
hists
,
struct
hists
*
pair_hists
,
bool
show_displacement
,
long
displacement
,
...
...
@@ -664,6 +756,13 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
ret
+=
snprintf
(
s
+
ret
,
size
-
ret
,
"%11"
PRIu64
,
nr_events
);
}
if
(
symbol_conf
.
show_total_period
)
{
if
(
sep
)
ret
+=
snprintf
(
s
+
ret
,
size
-
ret
,
"%c%"
PRIu64
,
*
sep
,
period
);
else
ret
+=
snprintf
(
s
+
ret
,
size
-
ret
,
" %12"
PRIu64
,
period
);
}
if
(
pair_hists
)
{
char
bf
[
32
];
double
old_percent
=
0
,
new_percent
=
0
,
diff
;
...
...
@@ -710,12 +809,16 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
return
ret
;
}
int
hist_entry__fprintf
(
struct
hist_entry
*
self
,
struct
hists
*
hists
,
int
hist_entry__fprintf
(
struct
hist_entry
*
he
,
size_t
size
,
struct
hists
*
hists
,
struct
hists
*
pair_hists
,
bool
show_displacement
,
long
displacement
,
FILE
*
fp
,
u64
session_total
)
{
char
bf
[
512
];
hist_entry__snprintf
(
self
,
bf
,
sizeof
(
bf
),
hists
,
pair_hists
,
if
(
size
==
0
||
size
>
sizeof
(
bf
))
size
=
sizeof
(
bf
);
hist_entry__snprintf
(
he
,
bf
,
size
,
hists
,
pair_hists
,
show_displacement
,
displacement
,
true
,
session_total
);
return
fprintf
(
fp
,
"%s
\n
"
,
bf
);
...
...
@@ -738,8 +841,9 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
left_margin
);
}
size_t
hists__fprintf
(
struct
hists
*
self
,
struct
hists
*
pair
,
bool
show_displacement
,
FILE
*
fp
)
size_t
hists__fprintf
(
struct
hists
*
hists
,
struct
hists
*
pair
,
bool
show_displacement
,
bool
show_header
,
int
max_rows
,
int
max_cols
,
FILE
*
fp
)
{
struct
sort_entry
*
se
;
struct
rb_node
*
nd
;
...
...
@@ -749,9 +853,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
unsigned
int
width
;
const
char
*
sep
=
symbol_conf
.
field_sep
;
const
char
*
col_width
=
symbol_conf
.
col_width_list_str
;
int
nr_rows
=
0
;
init_rem_hits
();
if
(
!
show_header
)
goto
print_entries
;
fprintf
(
fp
,
"# %s"
,
pair
?
"Baseline"
:
"Overhead"
);
if
(
symbol_conf
.
show_nr_samples
)
{
...
...
@@ -761,6 +869,13 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
fputs
(
" Samples "
,
fp
);
}
if
(
symbol_conf
.
show_total_period
)
{
if
(
sep
)
ret
+=
fprintf
(
fp
,
"%cPeriod"
,
*
sep
);
else
ret
+=
fprintf
(
fp
,
" Period "
);
}
if
(
symbol_conf
.
show_cpu_utilization
)
{
if
(
sep
)
{
ret
+=
fprintf
(
fp
,
"%csys"
,
*
sep
);
...
...
@@ -803,18 +918,21 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
width
=
strlen
(
se
->
se_header
);
if
(
symbol_conf
.
col_width_list_str
)
{
if
(
col_width
)
{
hists__set_col_len
(
self
,
se
->
se_width_idx
,
hists__set_col_len
(
hists
,
se
->
se_width_idx
,
atoi
(
col_width
));
col_width
=
strchr
(
col_width
,
','
);
if
(
col_width
)
++
col_width
;
}
}
if
(
!
hists__new_col_len
(
self
,
se
->
se_width_idx
,
width
))
width
=
hists__col_len
(
self
,
se
->
se_width_idx
);
if
(
!
hists__new_col_len
(
hists
,
se
->
se_width_idx
,
width
))
width
=
hists__col_len
(
hists
,
se
->
se_width_idx
);
fprintf
(
fp
,
" %*s"
,
width
,
se
->
se_header
);
}
fprintf
(
fp
,
"
\n
"
);
if
(
max_rows
&&
++
nr_rows
>=
max_rows
)
goto
out
;
if
(
sep
)
goto
print_entries
;
...
...
@@ -822,6 +940,8 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
fprintf
(
fp
,
"# ........"
);
if
(
symbol_conf
.
show_nr_samples
)
fprintf
(
fp
,
" .........."
);
if
(
symbol_conf
.
show_total_period
)
fprintf
(
fp
,
" ............"
);
if
(
pair
)
{
fprintf
(
fp
,
" .........."
);
if
(
show_displacement
)
...
...
@@ -834,17 +954,23 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
continue
;
fprintf
(
fp
,
" "
);
width
=
hists__col_len
(
self
,
se
->
se_width_idx
);
width
=
hists__col_len
(
hists
,
se
->
se_width_idx
);
if
(
width
==
0
)
width
=
strlen
(
se
->
se_header
);
for
(
i
=
0
;
i
<
width
;
i
++
)
fprintf
(
fp
,
"."
);
}
fprintf
(
fp
,
"
\n
#
\n
"
);
fprintf
(
fp
,
"
\n
"
);
if
(
max_rows
&&
++
nr_rows
>=
max_rows
)
goto
out
;
fprintf
(
fp
,
"#
\n
"
);
if
(
max_rows
&&
++
nr_rows
>=
max_rows
)
goto
out
;
print_entries:
for
(
nd
=
rb_first
(
&
self
->
entries
);
nd
;
nd
=
rb_next
(
nd
))
{
for
(
nd
=
rb_first
(
&
hists
->
entries
);
nd
;
nd
=
rb_next
(
nd
))
{
struct
hist_entry
*
h
=
rb_entry
(
nd
,
struct
hist_entry
,
rb_node
);
if
(
h
->
filtered
)
...
...
@@ -858,19 +984,22 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
displacement
=
0
;
++
position
;
}
ret
+=
hist_entry__fprintf
(
h
,
self
,
pair
,
show_displacement
,
displacement
,
fp
,
self
->
stats
.
total_period
);
ret
+=
hist_entry__fprintf
(
h
,
max_cols
,
hists
,
pair
,
show_displacement
,
displacement
,
fp
,
hists
->
stats
.
total_period
);
if
(
symbol_conf
.
use_callchain
)
ret
+=
hist_entry__fprintf_callchain
(
h
,
self
,
fp
,
self
->
stats
.
total_period
);
ret
+=
hist_entry__fprintf_callchain
(
h
,
hists
,
fp
,
hists
->
stats
.
total_period
);
if
(
max_rows
&&
++
nr_rows
>=
max_rows
)
goto
out
;
if
(
h
->
ms
.
map
==
NULL
&&
verbose
>
1
)
{
__map_groups__fprintf_maps
(
&
h
->
thread
->
mg
,
MAP__FUNCTION
,
verbose
,
fp
);
fprintf
(
fp
,
"%.10s end
\n
"
,
graph_dotted_line
);
}
}
out:
free
(
rem_sq_bracket
);
return
ret
;
...
...
@@ -879,7 +1008,7 @@ size_t hists__fprintf(struct hists *self, struct hists *pair,
/*
* See hists__fprintf to match the column widths
*/
unsigned
int
hists__sort_list_width
(
struct
hists
*
self
)
unsigned
int
hists__sort_list_width
(
struct
hists
*
hists
)
{
struct
sort_entry
*
se
;
int
ret
=
9
;
/* total % */
...
...
@@ -896,9 +1025,12 @@ unsigned int hists__sort_list_width(struct hists *self)
if
(
symbol_conf
.
show_nr_samples
)
ret
+=
11
;
if
(
symbol_conf
.
show_total_period
)
ret
+=
13
;
list_for_each_entry
(
se
,
&
hist_entry__sort_list
,
list
)
if
(
!
se
->
elide
)
ret
+=
2
+
hists__col_len
(
self
,
se
->
se_width_idx
);
ret
+=
2
+
hists__col_len
(
hists
,
se
->
se_width_idx
);
if
(
verbose
)
/* Addr + origin */
ret
+=
3
+
BITS_PER_LONG
/
4
;
...
...
@@ -906,32 +1038,32 @@ unsigned int hists__sort_list_width(struct hists *self)
return
ret
;
}
static
void
hists__remove_entry_filter
(
struct
hists
*
self
,
struct
hist_entry
*
h
,
static
void
hists__remove_entry_filter
(
struct
hists
*
hists
,
struct
hist_entry
*
h
,
enum
hist_filter
filter
)
{
h
->
filtered
&=
~
(
1
<<
filter
);
if
(
h
->
filtered
)
return
;
++
self
->
nr_entries
;
++
hists
->
nr_entries
;
if
(
h
->
ms
.
unfolded
)
self
->
nr_entries
+=
h
->
nr_rows
;
hists
->
nr_entries
+=
h
->
nr_rows
;
h
->
row_offset
=
0
;
self
->
stats
.
total_period
+=
h
->
period
;
self
->
stats
.
nr_events
[
PERF_RECORD_SAMPLE
]
+=
h
->
nr_events
;
hists
->
stats
.
total_period
+=
h
->
period
;
hists
->
stats
.
nr_events
[
PERF_RECORD_SAMPLE
]
+=
h
->
nr_events
;
hists__calc_col_len
(
self
,
h
);
hists__calc_col_len
(
hists
,
h
);
}
void
hists__filter_by_dso
(
struct
hists
*
self
,
const
struct
dso
*
dso
)
void
hists__filter_by_dso
(
struct
hists
*
hists
,
const
struct
dso
*
dso
)
{
struct
rb_node
*
nd
;
self
->
nr_entries
=
self
->
stats
.
total_period
=
0
;
self
->
stats
.
nr_events
[
PERF_RECORD_SAMPLE
]
=
0
;
hists__reset_col_len
(
self
);
hists
->
nr_entries
=
hists
->
stats
.
total_period
=
0
;
hists
->
stats
.
nr_events
[
PERF_RECORD_SAMPLE
]
=
0
;
hists__reset_col_len
(
hists
);
for
(
nd
=
rb_first
(
&
self
->
entries
);
nd
;
nd
=
rb_next
(
nd
))
{
for
(
nd
=
rb_first
(
&
hists
->
entries
);
nd
;
nd
=
rb_next
(
nd
))
{
struct
hist_entry
*
h
=
rb_entry
(
nd
,
struct
hist_entry
,
rb_node
);
if
(
symbol_conf
.
exclude_other
&&
!
h
->
parent
)
...
...
@@ -942,19 +1074,19 @@ void hists__filter_by_dso(struct hists *self, const struct dso *dso)
continue
;
}
hists__remove_entry_filter
(
self
,
h
,
HIST_FILTER__DSO
);
hists__remove_entry_filter
(
hists
,
h
,
HIST_FILTER__DSO
);
}
}
void
hists__filter_by_thread
(
struct
hists
*
self
,
const
struct
thread
*
thread
)
void
hists__filter_by_thread
(
struct
hists
*
hists
,
const
struct
thread
*
thread
)
{
struct
rb_node
*
nd
;
self
->
nr_entries
=
self
->
stats
.
total_period
=
0
;
self
->
stats
.
nr_events
[
PERF_RECORD_SAMPLE
]
=
0
;
hists__reset_col_len
(
self
);
hists
->
nr_entries
=
hists
->
stats
.
total_period
=
0
;
hists
->
stats
.
nr_events
[
PERF_RECORD_SAMPLE
]
=
0
;
hists__reset_col_len
(
hists
);
for
(
nd
=
rb_first
(
&
self
->
entries
);
nd
;
nd
=
rb_next
(
nd
))
{
for
(
nd
=
rb_first
(
&
hists
->
entries
);
nd
;
nd
=
rb_next
(
nd
))
{
struct
hist_entry
*
h
=
rb_entry
(
nd
,
struct
hist_entry
,
rb_node
);
if
(
thread
!=
NULL
&&
h
->
thread
!=
thread
)
{
...
...
@@ -962,7 +1094,7 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread)
continue
;
}
hists__remove_entry_filter
(
self
,
h
,
HIST_FILTER__THREAD
);
hists__remove_entry_filter
(
hists
,
h
,
HIST_FILTER__THREAD
);
}
}
...
...
@@ -976,13 +1108,13 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
return
symbol__annotate
(
he
->
ms
.
sym
,
he
->
ms
.
map
,
privsize
);
}
void
hists__inc_nr_events
(
struct
hists
*
self
,
u32
type
)
void
hists__inc_nr_events
(
struct
hists
*
hists
,
u32
type
)
{
++
self
->
stats
.
nr_events
[
0
];
++
self
->
stats
.
nr_events
[
type
];
++
hists
->
stats
.
nr_events
[
0
];
++
hists
->
stats
.
nr_events
[
type
];
}
size_t
hists__fprintf_nr_events
(
struct
hists
*
self
,
FILE
*
fp
)
size_t
hists__fprintf_nr_events
(
struct
hists
*
hists
,
FILE
*
fp
)
{
int
i
;
size_t
ret
=
0
;
...
...
@@ -990,7 +1122,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
for
(
i
=
0
;
i
<
PERF_RECORD_HEADER_MAX
;
++
i
)
{
const
char
*
name
;
if
(
self
->
stats
.
nr_events
[
i
]
==
0
)
if
(
hists
->
stats
.
nr_events
[
i
]
==
0
)
continue
;
name
=
perf_event__name
(
i
);
...
...
@@ -998,8 +1130,18 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
continue
;
ret
+=
fprintf
(
fp
,
"%16s events: %10d
\n
"
,
name
,
self
->
stats
.
nr_events
[
i
]);
hists
->
stats
.
nr_events
[
i
]);
}
return
ret
;
}
void
hists__init
(
struct
hists
*
hists
)
{
memset
(
hists
,
0
,
sizeof
(
*
hists
));
hists
->
entries_in_array
[
0
]
=
hists
->
entries_in_array
[
1
]
=
RB_ROOT
;
hists
->
entries_in
=
&
hists
->
entries_in_array
[
0
];
hists
->
entries_collapsed
=
RB_ROOT
;
hists
->
entries
=
RB_ROOT
;
pthread_mutex_init
(
&
hists
->
lock
,
NULL
);
}
tools/perf/util/hist.h
浏览文件 @
7588bada
...
...
@@ -2,6 +2,7 @@
#define __PERF_HIST_H
#include <linux/types.h>
#include <pthread.h>
#include "callchain.h"
extern
struct
callchain_param
callchain_param
;
...
...
@@ -43,8 +44,12 @@ enum hist_column {
};
struct
hists
{
struct
rb_root
entries_in_array
[
2
];
struct
rb_root
*
entries_in
;
struct
rb_root
entries
;
struct
rb_root
entries_collapsed
;
u64
nr_entries
;
pthread_mutex_t
lock
;
struct
events_stats
stats
;
u64
event_stream
;
u16
col_len
[
HISTC_NR_COLS
];
...
...
@@ -52,14 +57,16 @@ struct hists {
struct
callchain_cursor
callchain_cursor
;
};
void
hists__init
(
struct
hists
*
hists
);
struct
hist_entry
*
__hists__add_entry
(
struct
hists
*
self
,
struct
addr_location
*
al
,
struct
symbol
*
parent
,
u64
period
);
extern
int64_t
hist_entry__cmp
(
struct
hist_entry
*
,
struct
hist_entry
*
);
extern
int64_t
hist_entry__collapse
(
struct
hist_entry
*
,
struct
hist_entry
*
);
int
hist_entry__fprintf
(
struct
hist_entry
*
self
,
struct
hists
*
hists
,
int
hist_entry__fprintf
(
struct
hist_entry
*
he
,
size_t
size
,
struct
hists
*
hists
,
struct
hists
*
pair_hists
,
bool
show_displacement
,
long
displacement
,
FILE
*
fp
,
u64
total
);
long
displacement
,
FILE
*
fp
,
u64
session_
total
);
int
hist_entry__snprintf
(
struct
hist_entry
*
self
,
char
*
bf
,
size_t
size
,
struct
hists
*
hists
,
struct
hists
*
pair_hists
,
bool
show_displacement
,
long
displacement
,
...
...
@@ -67,13 +74,19 @@ int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
void
hist_entry__free
(
struct
hist_entry
*
);
void
hists__output_resort
(
struct
hists
*
self
);
void
hists__output_resort_threaded
(
struct
hists
*
hists
);
void
hists__collapse_resort
(
struct
hists
*
self
);
void
hists__collapse_resort_threaded
(
struct
hists
*
hists
);
void
hists__decay_entries
(
struct
hists
*
hists
);
void
hists__output_recalc_col_len
(
struct
hists
*
hists
,
int
max_rows
);
void
hists__inc_nr_events
(
struct
hists
*
self
,
u32
type
);
size_t
hists__fprintf_nr_events
(
struct
hists
*
self
,
FILE
*
fp
);
size_t
hists__fprintf
(
struct
hists
*
self
,
struct
hists
*
pair
,
bool
show_displacement
,
FILE
*
fp
);
bool
show_displacement
,
bool
show_header
,
int
max_rows
,
int
max_cols
,
FILE
*
fp
);
int
hist_entry__inc_addr_samples
(
struct
hist_entry
*
self
,
int
evidx
,
u64
addr
);
int
hist_entry__annotate
(
struct
hist_entry
*
self
,
size_t
privsize
);
...
...
@@ -90,13 +103,16 @@ struct perf_evlist;
#ifdef NO_NEWT_SUPPORT
static
inline
int
perf_evlist__tui_browse_hists
(
struct
perf_evlist
*
evlist
__used
,
const
char
*
help
__used
)
const
char
*
help
__used
,
void
(
*
timer
)(
void
*
arg
)
__used
,
void
*
arg
,
int
refresh
__used
)
{
return
0
;
}
static
inline
int
hist_entry__tui_annotate
(
struct
hist_entry
*
self
__used
,
int
evidx
__used
)
int
evidx
__used
,
int
nr_events
__used
,
void
(
*
timer
)(
void
*
arg
)
__used
,
void
*
arg
__used
,
int
delay_secs
__used
);
{
return
0
;
}
...
...
@@ -104,12 +120,15 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
#define KEY_RIGHT -2
#else
#include <newt.h>
int
hist_entry__tui_annotate
(
struct
hist_entry
*
self
,
int
evidx
);
int
hist_entry__tui_annotate
(
struct
hist_entry
*
he
,
int
evidx
,
int
nr_events
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
);
#define KEY_LEFT NEWT_KEY_LEFT
#define KEY_RIGHT NEWT_KEY_RIGHT
int
perf_evlist__tui_browse_hists
(
struct
perf_evlist
*
evlist
,
const
char
*
help
);
int
perf_evlist__tui_browse_hists
(
struct
perf_evlist
*
evlist
,
const
char
*
help
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
refresh
);
#endif
unsigned
int
hists__sort_list_width
(
struct
hists
*
self
);
...
...
tools/perf/util/session.c
浏览文件 @
7588bada
...
...
@@ -1326,3 +1326,22 @@ int perf_session__cpu_bitmap(struct perf_session *session,
return
0
;
}
void
perf_session__fprintf_info
(
struct
perf_session
*
session
,
FILE
*
fp
,
bool
full
)
{
struct
stat
st
;
int
ret
;
if
(
session
==
NULL
||
fp
==
NULL
)
return
;
ret
=
fstat
(
session
->
fd
,
&
st
);
if
(
ret
==
-
1
)
return
;
fprintf
(
fp
,
"# ========
\n
"
);
fprintf
(
fp
,
"# captured on: %s"
,
ctime
(
&
st
.
st_ctime
));
perf_header__fprintf_info
(
session
,
fp
,
full
);
fprintf
(
fp
,
"# ========
\n
#
\n
"
);
}
tools/perf/util/session.h
浏览文件 @
7588bada
...
...
@@ -177,4 +177,5 @@ void perf_session__print_ip(union perf_event *event,
int
perf_session__cpu_bitmap
(
struct
perf_session
*
session
,
const
char
*
cpu_list
,
unsigned
long
*
cpu_bitmap
);
void
perf_session__fprintf_info
(
struct
perf_session
*
s
,
FILE
*
fp
,
bool
full
);
#endif
/* __PERF_SESSION_H */
tools/perf/util/sort.h
浏览文件 @
7588bada
...
...
@@ -45,6 +45,7 @@ extern enum sort_type sort__first_dimension;
* @nr_rows - rows expanded in callchain, recalculated on folding/unfolding
*/
struct
hist_entry
{
struct
rb_node
rb_node_in
;
struct
rb_node
rb_node
;
u64
period
;
u64
period_sys
;
...
...
tools/perf/util/symbol.c
浏览文件 @
7588bada
...
...
@@ -46,7 +46,6 @@ struct symbol_conf symbol_conf = {
.
exclude_other
=
true
,
.
use_modules
=
true
,
.
try_vmlinux_path
=
true
,
.
annotate_asm_raw
=
true
,
.
annotate_src
=
true
,
.
symfs
=
""
,
};
...
...
tools/perf/util/symbol.h
浏览文件 @
7588bada
...
...
@@ -72,6 +72,7 @@ struct symbol_conf {
use_modules
,
sort_by_name
,
show_nr_samples
,
show_total_period
,
use_callchain
,
exclude_other
,
show_cpu_utilization
,
...
...
tools/perf/util/top.c
浏览文件 @
7588bada
...
...
@@ -15,52 +15,6 @@
#include "top.h"
#include <inttypes.h>
/*
* Ordering weight: count-1 * count-2 * ... / count-n
*/
static
double
sym_weight
(
const
struct
sym_entry
*
sym
,
struct
perf_top
*
top
)
{
double
weight
=
sym
->
snap_count
;
int
counter
;
if
(
!
top
->
display_weighted
)
return
weight
;
for
(
counter
=
1
;
counter
<
top
->
evlist
->
nr_entries
-
1
;
counter
++
)
weight
*=
sym
->
count
[
counter
];
weight
/=
(
sym
->
count
[
counter
]
+
1
);
return
weight
;
}
static
void
perf_top__remove_active_sym
(
struct
perf_top
*
top
,
struct
sym_entry
*
syme
)
{
pthread_mutex_lock
(
&
top
->
active_symbols_lock
);
list_del_init
(
&
syme
->
node
);
pthread_mutex_unlock
(
&
top
->
active_symbols_lock
);
}
static
void
rb_insert_active_sym
(
struct
rb_root
*
tree
,
struct
sym_entry
*
se
)
{
struct
rb_node
**
p
=
&
tree
->
rb_node
;
struct
rb_node
*
parent
=
NULL
;
struct
sym_entry
*
iter
;
while
(
*
p
!=
NULL
)
{
parent
=
*
p
;
iter
=
rb_entry
(
parent
,
struct
sym_entry
,
rb_node
);
if
(
se
->
weight
>
iter
->
weight
)
p
=
&
(
*
p
)
->
rb_left
;
else
p
=
&
(
*
p
)
->
rb_right
;
}
rb_link_node
(
&
se
->
rb_node
,
parent
,
p
);
rb_insert_color
(
&
se
->
rb_node
,
tree
);
}
#define SNPRINTF(buf, size, fmt, args...) \
({ \
size_t r = snprintf(buf, size, fmt, ## args); \
...
...
@@ -69,7 +23,6 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
size_t
perf_top__header_snprintf
(
struct
perf_top
*
top
,
char
*
bf
,
size_t
size
)
{
struct
perf_evsel
*
counter
;
float
samples_per_sec
=
top
->
samples
/
top
->
delay_secs
;
float
ksamples_per_sec
=
top
->
kernel_samples
/
top
->
delay_secs
;
float
esamples_percent
=
(
100
.
0
*
top
->
exact_samples
)
/
top
->
samples
;
...
...
@@ -104,7 +57,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
esamples_percent
);
}
if
(
top
->
evlist
->
nr_entries
==
1
||
!
top
->
display_weighted
)
{
if
(
top
->
evlist
->
nr_entries
==
1
)
{
struct
perf_evsel
*
first
;
first
=
list_entry
(
top
->
evlist
->
entries
.
next
,
struct
perf_evsel
,
node
);
ret
+=
SNPRINTF
(
bf
+
ret
,
size
-
ret
,
"%"
PRIu64
"%s "
,
...
...
@@ -112,27 +65,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
top
->
freq
?
"Hz"
:
""
);
}
if
(
!
top
->
display_weighted
)
{
ret
+=
SNPRINTF
(
bf
+
ret
,
size
-
ret
,
"%s"
,
event_name
(
top
->
sym_evsel
));
}
else
{
/*
* Don't let events eat all the space. Leaving 30 bytes
* for the rest should be enough.
*/
size_t
last_pos
=
size
-
30
;
list_for_each_entry
(
counter
,
&
top
->
evlist
->
entries
,
node
)
{
ret
+=
SNPRINTF
(
bf
+
ret
,
size
-
ret
,
"%s%s"
,
counter
->
idx
?
"/"
:
""
,
event_name
(
counter
));
if
(
ret
>
last_pos
)
{
sprintf
(
bf
+
last_pos
-
3
,
".."
);
ret
=
last_pos
-
1
;
break
;
}
}
}
ret
+=
SNPRINTF
(
bf
+
ret
,
size
-
ret
,
"%s"
,
event_name
(
top
->
sym_evsel
));
ret
+=
SNPRINTF
(
bf
+
ret
,
size
-
ret
,
"], "
);
...
...
@@ -166,73 +99,3 @@ void perf_top__reset_sample_counters(struct perf_top *top)
top
->
exact_samples
=
top
->
guest_kernel_samples
=
top
->
guest_us_samples
=
0
;
}
float
perf_top__decay_samples
(
struct
perf_top
*
top
,
struct
rb_root
*
root
)
{
struct
sym_entry
*
syme
,
*
n
;
float
sum_ksamples
=
0
.
0
;
int
snap
=
!
top
->
display_weighted
?
top
->
sym_evsel
->
idx
:
0
,
j
;
/* Sort the active symbols */
pthread_mutex_lock
(
&
top
->
active_symbols_lock
);
syme
=
list_entry
(
top
->
active_symbols
.
next
,
struct
sym_entry
,
node
);
pthread_mutex_unlock
(
&
top
->
active_symbols_lock
);
top
->
rb_entries
=
0
;
list_for_each_entry_safe_from
(
syme
,
n
,
&
top
->
active_symbols
,
node
)
{
syme
->
snap_count
=
syme
->
count
[
snap
];
if
(
syme
->
snap_count
!=
0
)
{
if
((
top
->
hide_user_symbols
&&
syme
->
map
->
dso
->
kernel
==
DSO_TYPE_USER
)
||
(
top
->
hide_kernel_symbols
&&
syme
->
map
->
dso
->
kernel
==
DSO_TYPE_KERNEL
))
{
perf_top__remove_active_sym
(
top
,
syme
);
continue
;
}
syme
->
weight
=
sym_weight
(
syme
,
top
);
if
((
int
)
syme
->
snap_count
>=
top
->
count_filter
)
{
rb_insert_active_sym
(
root
,
syme
);
++
top
->
rb_entries
;
}
sum_ksamples
+=
syme
->
snap_count
;
for
(
j
=
0
;
j
<
top
->
evlist
->
nr_entries
;
j
++
)
syme
->
count
[
j
]
=
top
->
zero
?
0
:
syme
->
count
[
j
]
*
7
/
8
;
}
else
perf_top__remove_active_sym
(
top
,
syme
);
}
return
sum_ksamples
;
}
/*
* Find the longest symbol name that will be displayed
*/
void
perf_top__find_widths
(
struct
perf_top
*
top
,
struct
rb_root
*
root
,
int
*
dso_width
,
int
*
dso_short_width
,
int
*
sym_width
)
{
struct
rb_node
*
nd
;
int
printed
=
0
;
*
sym_width
=
*
dso_width
=
*
dso_short_width
=
0
;
for
(
nd
=
rb_first
(
root
);
nd
;
nd
=
rb_next
(
nd
))
{
struct
sym_entry
*
syme
=
rb_entry
(
nd
,
struct
sym_entry
,
rb_node
);
struct
symbol
*
sym
=
sym_entry__symbol
(
syme
);
if
(
++
printed
>
top
->
print_entries
||
(
int
)
syme
->
snap_count
<
top
->
count_filter
)
continue
;
if
(
syme
->
map
->
dso
->
long_name_len
>
*
dso_width
)
*
dso_width
=
syme
->
map
->
dso
->
long_name_len
;
if
(
syme
->
map
->
dso
->
short_name_len
>
*
dso_short_width
)
*
dso_short_width
=
syme
->
map
->
dso
->
short_name_len
;
if
(
sym
->
namelen
>
*
sym_width
)
*
sym_width
=
sym
->
namelen
;
}
}
tools/perf/util/top.h
浏览文件 @
7588bada
...
...
@@ -4,64 +4,32 @@
#include "types.h"
#include "../perf.h"
#include <stddef.h>
#include <pthread.h>
#include <linux/list.h>
#include <linux/rbtree.h>
struct
perf_evlist
;
struct
perf_evsel
;
struct
perf_session
;
struct
sym_entry
{
struct
rb_node
rb_node
;
struct
list_head
node
;
unsigned
long
snap_count
;
double
weight
;
struct
map
*
map
;
unsigned
long
count
[
0
];
};
static
inline
struct
symbol
*
sym_entry__symbol
(
struct
sym_entry
*
self
)
{
return
((
void
*
)
self
)
+
symbol_conf
.
priv_size
;
}
struct
perf_top
{
struct
perf_evlist
*
evlist
;
/*
* Symbols will be added here in perf_event__process_sample and will
* get out after decayed.
*/
struct
list_head
active_symbols
;
pthread_mutex_t
active_symbols_lock
;
pthread_cond_t
active_symbols_cond
;
u64
samples
;
u64
kernel_samples
,
us_samples
;
u64
exact_samples
;
u64
guest_us_samples
,
guest_kernel_samples
;
u64
total_lost_warned
;
int
print_entries
,
count_filter
,
delay_secs
;
int
display_weighted
,
freq
,
rb_entries
;
int
freq
;
pid_t
target_pid
,
target_tid
;
bool
hide_kernel_symbols
,
hide_user_symbols
,
zero
;
const
char
*
cpu_list
;
struct
sym_entry
*
sym_filter_entry
;
struct
hist_entry
*
sym_filter_entry
;
struct
perf_evsel
*
sym_evsel
;
struct
perf_session
*
session
;
};
size_t
perf_top__header_snprintf
(
struct
perf_top
*
top
,
char
*
bf
,
size_t
size
);
void
perf_top__reset_sample_counters
(
struct
perf_top
*
top
);
float
perf_top__decay_samples
(
struct
perf_top
*
top
,
struct
rb_root
*
root
);
void
perf_top__find_widths
(
struct
perf_top
*
top
,
struct
rb_root
*
root
,
int
*
dso_width
,
int
*
dso_short_width
,
int
*
sym_width
);
#ifdef NO_NEWT_SUPPORT
static
inline
int
perf_top__tui_browser
(
struct
perf_top
*
top
__used
)
{
return
0
;
}
#else
int
perf_top__tui_browser
(
struct
perf_top
*
top
);
#endif
#endif
/* __PERF_TOP_H */
tools/perf/util/ui/browsers/annotate.c
浏览文件 @
7588bada
...
...
@@ -20,6 +20,7 @@ struct annotate_browser {
struct
ui_browser
b
;
struct
rb_root
entries
;
struct
rb_node
*
curr_hot
;
struct
objdump_line
*
selection
;
};
struct
objdump_line_rb_node
{
...
...
@@ -36,6 +37,7 @@ struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
static
void
annotate_browser__write
(
struct
ui_browser
*
self
,
void
*
entry
,
int
row
)
{
struct
annotate_browser
*
ab
=
container_of
(
self
,
struct
annotate_browser
,
b
);
struct
objdump_line
*
ol
=
rb_entry
(
entry
,
struct
objdump_line
,
node
);
bool
current_entry
=
ui_browser__is_current_entry
(
self
,
row
);
int
width
=
self
->
width
;
...
...
@@ -58,6 +60,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
if
(
!
current_entry
)
ui_browser__set_color
(
self
,
HE_COLORSET_CODE
);
else
ab
->
selection
=
ol
;
}
static
double
objdump_line__calc_percent
(
struct
objdump_line
*
self
,
...
...
@@ -141,7 +145,8 @@ static void annotate_browser__set_top(struct annotate_browser *self,
static
void
annotate_browser__calc_percent
(
struct
annotate_browser
*
browser
,
int
evidx
)
{
struct
symbol
*
sym
=
browser
->
b
.
priv
;
struct
map_symbol
*
ms
=
browser
->
b
.
priv
;
struct
symbol
*
sym
=
ms
->
sym
;
struct
annotation
*
notes
=
symbol__annotation
(
sym
);
struct
objdump_line
*
pos
;
...
...
@@ -164,21 +169,23 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
}
static
int
annotate_browser__run
(
struct
annotate_browser
*
self
,
int
evidx
,
int
refresh
)
int
nr_events
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
struct
rb_node
*
nd
=
NULL
;
struct
symbol
*
sym
=
self
->
b
.
priv
;
struct
map_symbol
*
ms
=
self
->
b
.
priv
;
struct
symbol
*
sym
=
ms
->
sym
;
/*
* RIGHT To allow builtin-annotate to cycle thru multiple symbols by
* examining the exit key for this function.
*/
int
exit_keys
[]
=
{
'H'
,
NEWT_KEY_TAB
,
NEWT_KEY_UNTAB
,
NEWT_KEY_RIGHT
,
0
};
NEWT_KEY_RIGHT
,
NEWT_KEY_ENTER
,
0
};
int
key
;
if
(
ui_browser__show
(
&
self
->
b
,
sym
->
name
,
"<-
, ->
or ESC: exit, TAB/shift+TAB: "
"cycle hottest lines, H: Hottest"
)
<
0
)
"<- or ESC: exit, TAB/shift+TAB: "
"cycle hottest lines, H: Hottest
, -> Line action
"
)
<
0
)
return
-
1
;
ui_browser__add_exit_keys
(
&
self
->
b
,
exit_keys
);
...
...
@@ -189,13 +196,13 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
nd
=
self
->
curr_hot
;
if
(
refresh
!=
0
)
newtFormSetTimer
(
self
->
b
.
form
,
refresh
);
if
(
delay_secs
!=
0
)
newtFormSetTimer
(
self
->
b
.
form
,
delay_secs
*
1000
);
while
(
1
)
{
key
=
ui_browser__run
(
&
self
->
b
);
if
(
refresh
!=
0
)
{
if
(
delay_secs
!=
0
)
{
annotate_browser__calc_percent
(
self
,
evidx
);
/*
* Current line focus got out of the list of most active
...
...
@@ -212,7 +219,10 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
* FIXME we need to check if it was
* es.reason == NEWT_EXIT_TIMER
*/
if
(
refresh
!=
0
)
if
(
timer
!=
NULL
)
timer
(
arg
);
if
(
delay_secs
!=
0
)
symbol__annotate_decay_histogram
(
sym
,
evidx
);
continue
;
case
NEWT_KEY_TAB
:
...
...
@@ -234,6 +244,57 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
case
'H'
:
nd
=
self
->
curr_hot
;
break
;
case
NEWT_KEY_ENTER
:
case
NEWT_KEY_RIGHT
:
if
(
self
->
selection
==
NULL
)
{
ui_helpline__puts
(
"Huh? No selection. Report to linux-kernel@vger.kernel.org"
);
continue
;
}
if
(
self
->
selection
->
offset
==
-
1
)
{
ui_helpline__puts
(
"Actions are only available for assembly lines."
);
continue
;
}
else
{
char
*
s
=
strstr
(
self
->
selection
->
line
,
"callq "
);
struct
annotation
*
notes
;
struct
symbol
*
target
;
u64
ip
;
if
(
s
==
NULL
)
{
ui_helpline__puts
(
"Actions are only available for the 'callq' instruction."
);
continue
;
}
s
=
strchr
(
s
,
' '
);
if
(
s
++
==
NULL
)
{
ui_helpline__puts
(
"Invallid callq instruction."
);
continue
;
}
ip
=
strtoull
(
s
,
NULL
,
16
);
ip
=
ms
->
map
->
map_ip
(
ms
->
map
,
ip
);
target
=
map__find_symbol
(
ms
->
map
,
ip
,
NULL
);
if
(
target
==
NULL
)
{
ui_helpline__puts
(
"The called function was not found."
);
continue
;
}
notes
=
symbol__annotation
(
target
);
pthread_mutex_lock
(
&
notes
->
lock
);
if
(
notes
->
src
==
NULL
&&
symbol__alloc_hist
(
target
,
nr_events
)
<
0
)
{
pthread_mutex_unlock
(
&
notes
->
lock
);
ui__warning
(
"Not enough memory for annotating '%s' symbol!
\n
"
,
target
->
name
);
continue
;
}
pthread_mutex_unlock
(
&
notes
->
lock
);
symbol__tui_annotate
(
target
,
ms
->
map
,
evidx
,
nr_events
,
timer
,
arg
,
delay_secs
);
}
break
;
default:
goto
out
;
}
...
...
@@ -246,22 +307,29 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
return
key
;
}
int
hist_entry__tui_annotate
(
struct
hist_entry
*
he
,
int
evidx
)
int
hist_entry__tui_annotate
(
struct
hist_entry
*
he
,
int
evidx
,
int
nr_events
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
return
symbol__tui_annotate
(
he
->
ms
.
sym
,
he
->
ms
.
map
,
evidx
,
0
);
return
symbol__tui_annotate
(
he
->
ms
.
sym
,
he
->
ms
.
map
,
evidx
,
nr_events
,
timer
,
arg
,
delay_secs
);
}
int
symbol__tui_annotate
(
struct
symbol
*
sym
,
struct
map
*
map
,
int
evidx
,
int
refresh
)
int
nr_events
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
struct
objdump_line
*
pos
,
*
n
;
struct
annotation
*
notes
;
struct
map_symbol
ms
=
{
.
map
=
map
,
.
sym
=
sym
,
};
struct
annotate_browser
browser
=
{
.
b
=
{
.
refresh
=
ui_browser__list_head_refresh
,
.
seek
=
ui_browser__list_head_seek
,
.
write
=
annotate_browser__write
,
.
priv
=
sym
,
.
priv
=
&
ms
,
},
};
int
ret
;
...
...
@@ -293,7 +361,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
browser
.
b
.
entries
=
&
notes
->
src
->
source
,
browser
.
b
.
width
+=
18
;
/* Percentage */
ret
=
annotate_browser__run
(
&
browser
,
evidx
,
refresh
);
ret
=
annotate_browser__run
(
&
browser
,
evidx
,
nr_events
,
timer
,
arg
,
delay_secs
);
list_for_each_entry_safe
(
pos
,
n
,
&
notes
->
src
->
source
,
node
)
{
list_del
(
&
pos
->
node
);
objdump_line__free
(
pos
);
...
...
tools/perf/util/ui/browsers/hists.c
浏览文件 @
7588bada
...
...
@@ -24,8 +24,15 @@ struct hist_browser {
struct
hists
*
hists
;
struct
hist_entry
*
he_selection
;
struct
map_symbol
*
selection
;
const
struct
thread
*
thread_filter
;
const
struct
dso
*
dso_filter
;
bool
has_symbols
;
};
static
int
hists__browser_title
(
struct
hists
*
self
,
char
*
bf
,
size_t
size
,
const
char
*
ev_name
,
const
struct
dso
*
dso
,
const
struct
thread
*
thread
);
static
void
hist_browser__refresh_dimensions
(
struct
hist_browser
*
self
)
{
/* 3 == +/- toggle symbol before actual hist_entry rendering */
...
...
@@ -290,28 +297,53 @@ static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
ui_browser__reset_index
(
&
self
->
b
);
}
static
int
hist_browser__run
(
struct
hist_browser
*
self
,
const
char
*
title
)
static
int
hist_browser__run
(
struct
hist_browser
*
self
,
const
char
*
ev_name
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
int
key
;
int
exit_keys
[]
=
{
'a'
,
'?'
,
'h'
,
'C'
,
'd'
,
'D'
,
'E'
,
't'
,
NEWT_KEY_ENTER
,
NEWT_KEY_RIGHT
,
NEWT_KEY_LEFT
,
NEWT_KEY_TAB
,
NEWT_KEY_UNTAB
,
0
,
};
int
delay_msecs
=
delay_secs
*
1000
;
char
title
[
160
];
int
sym_exit_keys
[]
=
{
'a'
,
'h'
,
'C'
,
'd'
,
'E'
,
't'
,
0
,
};
int
exit_keys
[]
=
{
'?'
,
'h'
,
'D'
,
NEWT_KEY_LEFT
,
NEWT_KEY_RIGHT
,
NEWT_KEY_TAB
,
NEWT_KEY_UNTAB
,
NEWT_KEY_ENTER
,
0
,
};
self
->
b
.
entries
=
&
self
->
hists
->
entries
;
self
->
b
.
nr_entries
=
self
->
hists
->
nr_entries
;
hist_browser__refresh_dimensions
(
self
);
hists__browser_title
(
self
->
hists
,
title
,
sizeof
(
title
),
ev_name
,
self
->
dso_filter
,
self
->
thread_filter
);
if
(
ui_browser__show
(
&
self
->
b
,
title
,
"Press '?' for help on key bindings"
)
<
0
)
return
-
1
;
if
(
timer
!=
NULL
)
newtFormSetTimer
(
self
->
b
.
form
,
delay_msecs
);
ui_browser__add_exit_keys
(
&
self
->
b
,
exit_keys
);
if
(
self
->
has_symbols
)
ui_browser__add_exit_keys
(
&
self
->
b
,
sym_exit_keys
);
while
(
1
)
{
key
=
ui_browser__run
(
&
self
->
b
);
switch
(
key
)
{
case
-
1
:
/* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
timer
(
arg
);
/*
* The timer may have changed the number of entries.
* XXX: Find better way to keep this in synch, probably
* removing this timer function altogether and just sync
* using the hists->lock...
*/
self
->
b
.
nr_entries
=
self
->
hists
->
nr_entries
;
hists__browser_title
(
self
->
hists
,
title
,
sizeof
(
title
),
ev_name
,
self
->
dso_filter
,
self
->
thread_filter
);
ui_browser__show_title
(
&
self
->
b
,
title
);
continue
;
case
'D'
:
{
/* Debug */
static
int
seq
;
struct
hist_entry
*
h
=
rb_entry
(
self
->
b
.
top
,
...
...
@@ -761,6 +793,7 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
self
->
hists
=
hists
;
self
->
b
.
refresh
=
hist_browser__refresh
;
self
->
b
.
seek
=
ui_browser__hists_seek
;
self
->
has_symbols
=
sort_sym
.
list
.
next
!=
NULL
;
}
return
self
;
...
...
@@ -803,16 +836,15 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
return
printed
;
}
static
int
perf_evsel__hists_browse
(
struct
perf_evsel
*
evsel
,
static
int
perf_evsel__hists_browse
(
struct
perf_evsel
*
evsel
,
int
nr_events
,
const
char
*
helpline
,
const
char
*
ev_name
,
bool
left_exits
)
bool
left_exits
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
struct
hists
*
self
=
&
evsel
->
hists
;
struct
hist_browser
*
browser
=
hist_browser__new
(
self
);
struct
pstack
*
fstack
;
const
struct
thread
*
thread_filter
=
NULL
;
const
struct
dso
*
dso_filter
=
NULL
;
char
msg
[
160
];
int
key
=
-
1
;
if
(
browser
==
NULL
)
...
...
@@ -824,8 +856,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
ui_helpline__push
(
helpline
);
hists__browser_title
(
self
,
msg
,
sizeof
(
msg
),
ev_name
,
dso_filter
,
thread_filter
);
while
(
1
)
{
const
struct
thread
*
thread
=
NULL
;
const
struct
dso
*
dso
=
NULL
;
...
...
@@ -834,7 +864,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
annotate
=
-
2
,
zoom_dso
=
-
2
,
zoom_thread
=
-
2
,
browse_map
=
-
2
;
key
=
hist_browser__run
(
browser
,
msg
);
key
=
hist_browser__run
(
browser
,
ev_name
,
timer
,
arg
,
delay_secs
);
if
(
browser
->
he_selection
!=
NULL
)
{
thread
=
hist_browser__selected_thread
(
browser
);
...
...
@@ -862,16 +892,17 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
case
NEWT_KEY_F1
:
case
'h'
:
case
'?'
:
ui__help_window
(
"-> Zoom into DSO/Threads & Annotate current symbol
\n
"
ui__help_window
(
"h/?/F1 Show this window
\n
"
"TAB/UNTAB Switch events
\n
"
"q/CTRL+C Exit browser
\n\n
"
"For symbolic views (--sort has sym):
\n\n
"
"-> Zoom into DSO/Threads & Annotate current symbol
\n
"
"<- Zoom out
\n
"
"a Annotate current symbol
\n
"
"h/?/F1 Show this window
\n
"
"C Collapse all callchains
\n
"
"E Expand all callchains
\n
"
"d Zoom into current DSO
\n
"
"t Zoom into current Thread
\n
"
"TAB/UNTAB Switch events
\n
"
"q/CTRL+C Exit browser"
);
"t Zoom into current Thread
\n
"
);
continue
;
case
NEWT_KEY_ENTER
:
case
NEWT_KEY_RIGHT
:
...
...
@@ -889,9 +920,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
continue
;
}
top
=
pstack__pop
(
fstack
);
if
(
top
==
&
dso_filter
)
if
(
top
==
&
browser
->
dso_filter
)
goto
zoom_out_dso
;
if
(
top
==
&
thread_filter
)
if
(
top
==
&
browser
->
thread_filter
)
goto
zoom_out_thread
;
continue
;
}
...
...
@@ -904,6 +935,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
goto
out_free_stack
;
}
if
(
!
browser
->
has_symbols
)
goto
add_exit_option
;
if
(
browser
->
selection
!=
NULL
&&
browser
->
selection
->
sym
!=
NULL
&&
!
browser
->
selection
->
map
->
dso
->
annotate_warned
&&
...
...
@@ -913,14 +947,14 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
if
(
thread
!=
NULL
&&
asprintf
(
&
options
[
nr_options
],
"Zoom %s %s(%d) thread"
,
(
thread_filter
?
"out of"
:
"into"
),
(
browser
->
thread_filter
?
"out of"
:
"into"
),
(
thread
->
comm_set
?
thread
->
comm
:
""
),
thread
->
pid
)
>
0
)
zoom_thread
=
nr_options
++
;
if
(
dso
!=
NULL
&&
asprintf
(
&
options
[
nr_options
],
"Zoom %s %s DSO"
,
(
dso_filter
?
"out of"
:
"into"
),
(
browser
->
dso_filter
?
"out of"
:
"into"
),
(
dso
->
kernel
?
"the Kernel"
:
dso
->
short_name
))
>
0
)
zoom_dso
=
nr_options
++
;
...
...
@@ -928,7 +962,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
browser
->
selection
->
map
!=
NULL
&&
asprintf
(
&
options
[
nr_options
],
"Browse map details"
)
>
0
)
browse_map
=
nr_options
++
;
add_exit_option:
options
[
nr_options
++
]
=
(
char
*
)
"Exit"
;
choice
=
ui__popup_menu
(
nr_options
,
options
);
...
...
@@ -949,45 +983,42 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel,
if
(
he
==
NULL
)
continue
;
hist_entry__tui_annotate
(
he
,
evsel
->
idx
);
hist_entry__tui_annotate
(
he
,
evsel
->
idx
,
nr_events
,
timer
,
arg
,
delay_secs
);
}
else
if
(
choice
==
browse_map
)
map__browse
(
browser
->
selection
->
map
);
else
if
(
choice
==
zoom_dso
)
{
zoom_dso:
if
(
dso_filter
)
{
pstack__remove
(
fstack
,
&
dso_filter
);
if
(
browser
->
dso_filter
)
{
pstack__remove
(
fstack
,
&
browser
->
dso_filter
);
zoom_out_dso:
ui_helpline__pop
();
dso_filter
=
NULL
;
browser
->
dso_filter
=
NULL
;
}
else
{
if
(
dso
==
NULL
)
continue
;
ui_helpline__fpush
(
"To zoom out press <- or -> +
\"
Zoom out of %s DSO
\"
"
,
dso
->
kernel
?
"the Kernel"
:
dso
->
short_name
);
dso_filter
=
dso
;
pstack__push
(
fstack
,
&
dso_filter
);
browser
->
dso_filter
=
dso
;
pstack__push
(
fstack
,
&
browser
->
dso_filter
);
}
hists__filter_by_dso
(
self
,
dso_filter
);
hists__browser_title
(
self
,
msg
,
sizeof
(
msg
),
ev_name
,
dso_filter
,
thread_filter
);
hists__filter_by_dso
(
self
,
browser
->
dso_filter
);
hist_browser__reset
(
browser
);
}
else
if
(
choice
==
zoom_thread
)
{
zoom_thread:
if
(
thread_filter
)
{
pstack__remove
(
fstack
,
&
thread_filter
);
if
(
browser
->
thread_filter
)
{
pstack__remove
(
fstack
,
&
browser
->
thread_filter
);
zoom_out_thread:
ui_helpline__pop
();
thread_filter
=
NULL
;
browser
->
thread_filter
=
NULL
;
}
else
{
ui_helpline__fpush
(
"To zoom out press <- or -> +
\"
Zoom out of %s(%d) thread
\"
"
,
thread
->
comm_set
?
thread
->
comm
:
""
,
thread
->
pid
);
thread_filter
=
thread
;
pstack__push
(
fstack
,
&
thread_filter
);
browser
->
thread_filter
=
thread
;
pstack__push
(
fstack
,
&
browser
->
thread_filter
);
}
hists__filter_by_thread
(
self
,
thread_filter
);
hists__browser_title
(
self
,
msg
,
sizeof
(
msg
),
ev_name
,
dso_filter
,
thread_filter
);
hists__filter_by_thread
(
self
,
browser
->
thread_filter
);
hist_browser__reset
(
browser
);
}
}
...
...
@@ -1026,9 +1057,12 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
menu
->
selection
=
evsel
;
}
static
int
perf_evsel_menu__run
(
struct
perf_evsel_menu
*
menu
,
const
char
*
help
)
static
int
perf_evsel_menu__run
(
struct
perf_evsel_menu
*
menu
,
int
nr_events
,
const
char
*
help
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
int
exit_keys
[]
=
{
NEWT_KEY_ENTER
,
NEWT_KEY_RIGHT
,
0
,
};
int
delay_msecs
=
delay_secs
*
1000
;
struct
perf_evlist
*
evlist
=
menu
->
b
.
priv
;
struct
perf_evsel
*
pos
;
const
char
*
ev_name
,
*
title
=
"Available samples"
;
...
...
@@ -1038,20 +1072,30 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
"ESC: exit, ENTER|->: Browse histograms"
)
<
0
)
return
-
1
;
if
(
timer
!=
NULL
)
newtFormSetTimer
(
menu
->
b
.
form
,
delay_msecs
);
ui_browser__add_exit_keys
(
&
menu
->
b
,
exit_keys
);
while
(
1
)
{
key
=
ui_browser__run
(
&
menu
->
b
);
switch
(
key
)
{
case
-
1
:
/* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
timer
(
arg
);
continue
;
case
NEWT_KEY_RIGHT
:
case
NEWT_KEY_ENTER
:
if
(
!
menu
->
selection
)
continue
;
pos
=
menu
->
selection
;
perf_evlist__set_selected
(
evlist
,
pos
);
browse_hists:
ev_name
=
event_name
(
pos
);
key
=
perf_evsel__hists_browse
(
pos
,
help
,
ev_name
,
true
);
key
=
perf_evsel__hists_browse
(
pos
,
nr_events
,
help
,
ev_name
,
true
,
timer
,
arg
,
delay_secs
);
ui_browser__show_title
(
&
menu
->
b
,
title
);
break
;
case
NEWT_KEY_LEFT
:
...
...
@@ -1070,12 +1114,14 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
pos
=
list_entry
(
evlist
->
entries
.
next
,
struct
perf_evsel
,
node
);
else
pos
=
list_entry
(
pos
->
node
.
next
,
struct
perf_evsel
,
node
);
perf_evlist__set_selected
(
evlist
,
pos
);
goto
browse_hists
;
case
NEWT_KEY_UNTAB
:
if
(
pos
->
node
.
prev
==
&
evlist
->
entries
)
pos
=
list_entry
(
evlist
->
entries
.
prev
,
struct
perf_evsel
,
node
);
else
pos
=
list_entry
(
pos
->
node
.
prev
,
struct
perf_evsel
,
node
);
perf_evlist__set_selected
(
evlist
,
pos
);
goto
browse_hists
;
case
'q'
:
case
CTRL
(
'c'
):
...
...
@@ -1091,7 +1137,9 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, const char *help)
}
static
int
__perf_evlist__tui_browse_hists
(
struct
perf_evlist
*
evlist
,
const
char
*
help
)
const
char
*
help
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
struct
perf_evsel
*
pos
;
struct
perf_evsel_menu
menu
=
{
...
...
@@ -1121,18 +1169,24 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
pos
->
name
=
strdup
(
ev_name
);
}
return
perf_evsel_menu__run
(
&
menu
,
help
);
return
perf_evsel_menu__run
(
&
menu
,
evlist
->
nr_entries
,
help
,
timer
,
arg
,
delay_secs
);
}
int
perf_evlist__tui_browse_hists
(
struct
perf_evlist
*
evlist
,
const
char
*
help
)
int
perf_evlist__tui_browse_hists
(
struct
perf_evlist
*
evlist
,
const
char
*
help
,
void
(
*
timer
)(
void
*
arg
),
void
*
arg
,
int
delay_secs
)
{
if
(
evlist
->
nr_entries
==
1
)
{
struct
perf_evsel
*
first
=
list_entry
(
evlist
->
entries
.
next
,
struct
perf_evsel
,
node
);
const
char
*
ev_name
=
event_name
(
first
);
return
perf_evsel__hists_browse
(
first
,
help
,
ev_name
,
false
);
return
perf_evsel__hists_browse
(
first
,
evlist
->
nr_entries
,
help
,
ev_name
,
false
,
timer
,
arg
,
delay_secs
);
}
return
__perf_evlist__tui_browse_hists
(
evlist
,
help
);
return
__perf_evlist__tui_browse_hists
(
evlist
,
help
,
timer
,
arg
,
delay_secs
);
}
tools/perf/util/ui/browsers/top.c
已删除
100644 → 0
浏览文件 @
d48b0e17
/*
* Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
*
* Parts came from builtin-{top,stat,record}.c, see those files for further
* copyright notes.
*
* Released under the GPL v2. (and only v2, not any later version)
*/
#include "../browser.h"
#include "../../annotate.h"
#include "../helpline.h"
#include "../libslang.h"
#include "../util.h"
#include "../ui.h"
#include "../../evlist.h"
#include "../../hist.h"
#include "../../sort.h"
#include "../../symbol.h"
#include "../../session.h"
#include "../../top.h"
struct
perf_top_browser
{
struct
ui_browser
b
;
struct
rb_root
root
;
struct
sym_entry
*
selection
;
float
sum_ksamples
;
int
dso_width
;
int
dso_short_width
;
int
sym_width
;
};
static
void
perf_top_browser__write
(
struct
ui_browser
*
browser
,
void
*
entry
,
int
row
)
{
struct
perf_top_browser
*
top_browser
=
container_of
(
browser
,
struct
perf_top_browser
,
b
);
struct
sym_entry
*
syme
=
rb_entry
(
entry
,
struct
sym_entry
,
rb_node
);
bool
current_entry
=
ui_browser__is_current_entry
(
browser
,
row
);
struct
symbol
*
symbol
=
sym_entry__symbol
(
syme
);
struct
perf_top
*
top
=
browser
->
priv
;
int
width
=
browser
->
width
;
double
pcnt
;
pcnt
=
100
.
0
-
(
100
.
0
*
((
top_browser
->
sum_ksamples
-
syme
->
snap_count
)
/
top_browser
->
sum_ksamples
));
ui_browser__set_percent_color
(
browser
,
pcnt
,
current_entry
);
if
(
top
->
evlist
->
nr_entries
==
1
||
!
top
->
display_weighted
)
{
slsmg_printf
(
"%20.2f "
,
syme
->
weight
);
width
-=
21
;
}
else
{
slsmg_printf
(
"%9.1f %10ld "
,
syme
->
weight
,
syme
->
snap_count
);
width
-=
20
;
}
slsmg_printf
(
"%4.1f%%"
,
pcnt
);
width
-=
7
;
if
(
verbose
)
{
slsmg_printf
(
" %016"
PRIx64
,
symbol
->
start
);
width
-=
17
;
}
slsmg_printf
(
" %-*.*s "
,
top_browser
->
sym_width
,
top_browser
->
sym_width
,
symbol
->
name
);
width
-=
top_browser
->
sym_width
;
slsmg_write_nstring
(
width
>=
syme
->
map
->
dso
->
long_name_len
?
syme
->
map
->
dso
->
long_name
:
syme
->
map
->
dso
->
short_name
,
width
);
if
(
current_entry
)
top_browser
->
selection
=
syme
;
}
static
void
perf_top_browser__update_rb_tree
(
struct
perf_top_browser
*
browser
)
{
struct
perf_top
*
top
=
browser
->
b
.
priv
;
u64
top_idx
=
browser
->
b
.
top_idx
;
browser
->
root
=
RB_ROOT
;
browser
->
b
.
top
=
NULL
;
browser
->
sum_ksamples
=
perf_top__decay_samples
(
top
,
&
browser
->
root
);
/*
* No active symbols
*/
if
(
top
->
rb_entries
==
0
)
return
;
perf_top__find_widths
(
top
,
&
browser
->
root
,
&
browser
->
dso_width
,
&
browser
->
dso_short_width
,
&
browser
->
sym_width
);
if
(
browser
->
sym_width
+
browser
->
dso_width
>
browser
->
b
.
width
-
29
)
{
browser
->
dso_width
=
browser
->
dso_short_width
;
if
(
browser
->
sym_width
+
browser
->
dso_width
>
browser
->
b
.
width
-
29
)
browser
->
sym_width
=
browser
->
b
.
width
-
browser
->
dso_width
-
29
;
}
/*
* Adjust the ui_browser indexes since the entries in the browser->root
* rb_tree may have changed, then seek it from start, so that we get a
* possible new top of the screen.
*/
browser
->
b
.
nr_entries
=
top
->
rb_entries
;
if
(
top_idx
>=
browser
->
b
.
nr_entries
)
{
if
(
browser
->
b
.
height
>=
browser
->
b
.
nr_entries
)
top_idx
=
browser
->
b
.
nr_entries
-
browser
->
b
.
height
;
else
top_idx
=
0
;
}
if
(
browser
->
b
.
index
>=
top_idx
+
browser
->
b
.
height
)
browser
->
b
.
index
=
top_idx
+
browser
->
b
.
index
-
browser
->
b
.
top_idx
;
if
(
browser
->
b
.
index
>=
browser
->
b
.
nr_entries
)
browser
->
b
.
index
=
browser
->
b
.
nr_entries
-
1
;
browser
->
b
.
top_idx
=
top_idx
;
browser
->
b
.
seek
(
&
browser
->
b
,
top_idx
,
SEEK_SET
);
}
static
void
perf_top_browser__annotate
(
struct
perf_top_browser
*
browser
)
{
struct
sym_entry
*
syme
=
browser
->
selection
;
struct
symbol
*
sym
=
sym_entry__symbol
(
syme
);
struct
annotation
*
notes
=
symbol__annotation
(
sym
);
struct
perf_top
*
top
=
browser
->
b
.
priv
;
if
(
notes
->
src
!=
NULL
)
goto
do_annotation
;
pthread_mutex_lock
(
&
notes
->
lock
);
top
->
sym_filter_entry
=
NULL
;
if
(
symbol__alloc_hist
(
sym
,
top
->
evlist
->
nr_entries
)
<
0
)
{
pr_err
(
"Not enough memory for annotating '%s' symbol!
\n
"
,
sym
->
name
);
pthread_mutex_unlock
(
&
notes
->
lock
);
return
;
}
top
->
sym_filter_entry
=
syme
;
pthread_mutex_unlock
(
&
notes
->
lock
);
do_annotation:
symbol__tui_annotate
(
sym
,
syme
->
map
,
0
,
top
->
delay_secs
*
1000
);
}
static
void
perf_top_browser__warn_lost
(
struct
perf_top_browser
*
browser
)
{
struct
perf_top
*
top
=
browser
->
b
.
priv
;
char
msg
[
128
];
int
len
;
top
->
total_lost_warned
=
top
->
session
->
hists
.
stats
.
total_lost
;
pthread_mutex_lock
(
&
ui__lock
);
ui_browser__set_color
(
&
browser
->
b
,
HE_COLORSET_TOP
);
len
=
snprintf
(
msg
,
sizeof
(
msg
),
" WARNING: LOST %"
PRIu64
" events, Check IO/CPU overload"
,
top
->
total_lost_warned
);
if
(
len
>
browser
->
b
.
width
)
len
=
browser
->
b
.
width
;
SLsmg_gotorc
(
0
,
browser
->
b
.
width
-
len
);
slsmg_write_nstring
(
msg
,
len
);
pthread_mutex_unlock
(
&
ui__lock
);
}
static
int
perf_top_browser__run
(
struct
perf_top_browser
*
browser
)
{
int
key
;
char
title
[
160
];
struct
perf_top
*
top
=
browser
->
b
.
priv
;
int
delay_msecs
=
top
->
delay_secs
*
1000
;
int
exit_keys
[]
=
{
'a'
,
NEWT_KEY_ENTER
,
NEWT_KEY_RIGHT
,
0
,
};
perf_top_browser__update_rb_tree
(
browser
);
perf_top__header_snprintf
(
top
,
title
,
sizeof
(
title
));
perf_top__reset_sample_counters
(
top
);
if
(
ui_browser__show
(
&
browser
->
b
,
title
,
"ESC: exit, ENTER|->|a: Live Annotate"
)
<
0
)
return
-
1
;
newtFormSetTimer
(
browser
->
b
.
form
,
delay_msecs
);
ui_browser__add_exit_keys
(
&
browser
->
b
,
exit_keys
);
while
(
1
)
{
key
=
ui_browser__run
(
&
browser
->
b
);
switch
(
key
)
{
case
-
1
:
/* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */
perf_top_browser__update_rb_tree
(
browser
);
perf_top__header_snprintf
(
top
,
title
,
sizeof
(
title
));
perf_top__reset_sample_counters
(
top
);
ui_browser__set_color
(
&
browser
->
b
,
NEWT_COLORSET_ROOT
);
SLsmg_gotorc
(
0
,
0
);
slsmg_write_nstring
(
title
,
browser
->
b
.
width
);
if
(
top
->
total_lost_warned
!=
top
->
session
->
hists
.
stats
.
total_lost
)
perf_top_browser__warn_lost
(
browser
);
break
;
case
'a'
:
case
NEWT_KEY_RIGHT
:
case
NEWT_KEY_ENTER
:
if
(
browser
->
selection
)
perf_top_browser__annotate
(
browser
);
break
;
case
NEWT_KEY_LEFT
:
continue
;
case
NEWT_KEY_ESCAPE
:
if
(
!
ui__dialog_yesno
(
"Do you really want to exit?"
))
continue
;
/* Fall thru */
default:
goto
out
;
}
}
out:
ui_browser__hide
(
&
browser
->
b
);
return
key
;
}
int
perf_top__tui_browser
(
struct
perf_top
*
top
)
{
struct
perf_top_browser
browser
=
{
.
b
=
{
.
entries
=
&
browser
.
root
,
.
refresh
=
ui_browser__rb_tree_refresh
,
.
seek
=
ui_browser__rb_tree_seek
,
.
write
=
perf_top_browser__write
,
.
priv
=
top
,
},
};
return
perf_top_browser__run
(
&
browser
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录