perf/core improvements and fixes:

perf annotate:
 
   Mao Han:
 
   - Add support for the csky processor architecture.
 
 perf stat:
 
   Andi Kleen:
 
   - Fix metrics with --no-merge.
 
   - Don't merge events in the same PMU.
 
   - Fix group lookup for metric group.
 
 Intel PT:
 
   Adrian Hunter:
 
   - Improve CBR (Core to Bus Ratio) packets support.
 
   - Fix thread stack return from kernel for kernel only case.
 
   - Export power and ptwrite events to sqlite and postgresql.
 
 core libraries:
 
   Arnaldo Carvalho de Melo:
 
   - Find routines in tools/perf/util/ that have implementations in the kernel
     libraries (lib/*.c), such as strreplace(), strim(), skip_spaces() and reuse
     them after making a copy into tools/lib and tools/include/.
 
     This continues the effort of having tools/ code looking as much as possible
     like kernel source code, to help encourage people to work on both the kernel
     and in tools hosted in the kernel sources.
 
     That in turn will help moving stuff that uses those routines to
     tools/lib/perf/ where they will be made available for use in other tools.
 
     In the process ditch old cruft, remove unused variables and add missing
     include directives for headers providing things used in places that were
     building by sheer luck.
 
   Kyle Meyer:
 
   - Bump MAX_NR_CPUS and MAX_CACHES to get these tools to work on more machines.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCXRq6NgAKCRCyPKLppCJ+
 J6ekAP48ZwkxFF2kET3fgIwOL6G4+cQ8t7s2Mz1lYqLDW24NqAEAqNSpKdT60mKy
 6o+ZWjb2PtTt2F26OdoPoZvx8Txvgw8=
 =cxKY
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo-5.3-20190701' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

perf annotate:

  Mao Han:

  - Add support for the csky processor architecture.

perf stat:

  Andi Kleen:

  - Fix metrics with --no-merge.

  - Don't merge events in the same PMU.

  - Fix group lookup for metric group.

Intel PT:

  Adrian Hunter:

  - Improve CBR (Core to Bus Ratio) packets support.

  - Fix thread stack return from kernel for kernel only case.

  - Export power and ptwrite events to sqlite and postgresql.

core libraries:

  Arnaldo Carvalho de Melo:

  - Find routines in tools/perf/util/ that have implementations in the kernel
    libraries (lib/*.c), such as strreplace(), strim(), skip_spaces() and reuse
    them after making a copy into tools/lib and tools/include/.

    This continues the effort of having tools/ code looking as much as possible
    like kernel source code, to help encourage people to work on both the kernel
    and in tools hosted in the kernel sources.

    That in turn will help moving stuff that uses those routines to
    tools/lib/perf/ where they will be made available for use in other tools.

    In the process ditch old cruft, remove unused variables and add missing
    include directives for headers providing things used in places that were
    building by sheer luck.

  Kyle Meyer:

  - Bump MAX_NR_CPUS and MAX_CACHES to get these tools to work on more machines.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2019-07-03 15:54:24 +02:00
commit a041ede090
79 changed files with 1167 additions and 450 deletions

View File

@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H
/*
* NOTE! This ctype does not handle EOF like the standard C
* library is required to.
*/
#define _U 0x01 /* upper */
#define _L 0x02 /* lower */
#define _D 0x04 /* digit */
#define _C 0x08 /* cntrl */
#define _P 0x10 /* punct */
#define _S 0x20 /* white space (space/lf/tab) */
#define _X 0x40 /* hex digit */
#define _SP 0x80 /* hard space (0x20) */
extern const unsigned char _ctype[];
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
static inline int __isdigit(int c)
{
return '0' <= c && c <= '9';
}
#define isdigit(c) __isdigit(c)
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
/* Note: isspace() must return false for %NUL-terminator */
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)
static inline unsigned char __tolower(unsigned char c)
{
if (isupper(c))
c -= 'A'-'a';
return c;
}
static inline unsigned char __toupper(unsigned char c)
{
if (islower(c))
c -= 'a'-'A';
return c;
}
#define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)
/*
* Fast implementation of tolower() for internal usage. Do not use in your
* code.
*/
static inline char _tolower(const char c)
{
return c | 0x20;
}
/* Fast check for octal digit */
static inline int isodigit(const char c)
{
return c >= '0' && c <= '7';
}
#endif

View File

@ -7,6 +7,9 @@
void *memdup(const void *src, size_t len);
char **argv_split(const char *str, int *argcp);
void argv_free(char **argv);
int strtobool(const char *s, bool *res);
/*
@ -19,6 +22,8 @@ extern size_t strlcpy(char *dest, const char *src, size_t size);
char *str_error_r(int errnum, char *buf, size_t buflen);
char *strreplace(char *s, char old, char new);
/**
* strstarts - does @str start with @prefix?
* @str: string to examine
@ -29,4 +34,8 @@ static inline bool strstarts(const char *str, const char *prefix)
return strncmp(str, prefix, strlen(prefix)) == 0;
}
#endif /* _LINUX_STRING_H_ */
extern char * __must_check skip_spaces(const char *);
extern char *strim(char *);
#endif /* _TOOLS_LINUX_STRING_H_ */

100
tools/lib/argv_split.c Normal file
View File

@ -0,0 +1,100 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Helper function for splitting a string into an argv-like array.
*/
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/string.h>
static const char *skip_arg(const char *cp)
{
while (*cp && !isspace(*cp))
cp++;
return cp;
}
static int count_argc(const char *str)
{
int count = 0;
while (*str) {
str = skip_spaces(str);
if (*str) {
count++;
str = skip_arg(str);
}
}
return count;
}
/**
* argv_free - free an argv
* @argv - the argument vector to be freed
*
* Frees an argv and the strings it points to.
*/
void argv_free(char **argv)
{
char **p;
for (p = argv; *p; p++) {
free(*p);
*p = NULL;
}
free(argv);
}
/**
* argv_split - split a string at whitespace, returning an argv
* @str: the string to be split
* @argcp: returned argument count
*
* Returns an array of pointers to strings which are split out from
* @str. This is performed by strictly splitting on white-space; no
* quote processing is performed. Multiple whitespace characters are
* considered to be a single argument separator. The returned array
* is always NULL-terminated. Returns NULL on memory allocation
* failure.
*/
char **argv_split(const char *str, int *argcp)
{
int argc = count_argc(str);
char **argv = calloc(argc + 1, sizeof(*argv));
char **argvp;
if (argv == NULL)
goto out;
if (argcp)
*argcp = argc;
argvp = argv;
while (*str) {
str = skip_spaces(str);
if (*str) {
const char *p = str;
char *t;
str = skip_arg(str);
t = strndup(p, str-p);
if (t == NULL)
goto fail;
*argvp++ = t;
}
}
*argvp = NULL;
out:
return argv;
fail:
argv_free(argv);
return NULL;
}

35
tools/lib/ctype.c Normal file
View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-2.0
/*
* linux/lib/ctype.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
#include <linux/ctype.h>
#include <linux/compiler.h>
const unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */

View File

@ -17,6 +17,7 @@
#include <string.h>
#include <errno.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/compiler.h>
/**
@ -106,3 +107,57 @@ size_t __weak strlcpy(char *dest, const char *src, size_t size)
}
return ret;
}
/**
* skip_spaces - Removes leading whitespace from @str.
* @str: The string to be stripped.
*
* Returns a pointer to the first non-whitespace character in @str.
*/
char *skip_spaces(const char *str)
{
while (isspace(*str))
++str;
return (char *)str;
}
/**
* strim - Removes leading and trailing whitespace from @s.
* @s: The string to be stripped.
*
* Note that the first trailing whitespace is replaced with a %NUL-terminator
* in the given string @s. Returns a pointer to the first non-whitespace
* character in @s.
*/
char *strim(char *s)
{
size_t size;
char *end;
size = strlen(s);
if (!size)
return s;
end = s + size - 1;
while (end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
return skip_spaces(s);
}
/**
* strreplace - Replace all occurrences of character in string.
* @s: The string to operate on.
* @old: The character being replaced.
* @new: The character @old is replaced with.
*
* Returns pointer to the nul byte at the end of @s.
*/
char *strreplace(char *s, char old, char new)
{
for (; *s; ++s)
if (*s == old)
*s = new;
return s;
}

View File

@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#include <ctype.h>
#include "symbol/kallsyms.h"
#include <stdio.h>
#include <stdlib.h>
@ -16,6 +15,19 @@ bool kallsyms__is_function(char symbol_type)
return symbol_type == 'T' || symbol_type == 'W';
}
/*
* While we find nice hex chars, build a long_val.
* Return number of chars processed.
*/
int hex2u64(const char *ptr, u64 *long_val)
{
char *p;
*long_val = strtoull(ptr, &p, 16);
return p - ptr;
}
int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name,
char type, u64 start))

View File

@ -18,6 +18,8 @@ static inline u8 kallsyms2elf_binding(char type)
return isupper(type) ? STB_GLOBAL : STB_LOCAL;
}
int hex2u64(const char *ptr, u64 *long_val);
u8 kallsyms2elf_type(char type);
bool kallsyms__is_function(char symbol_type);

View File

@ -7,6 +7,8 @@ tools/lib/traceevent
tools/lib/api
tools/lib/bpf
tools/lib/subcmd
tools/lib/argv_split.c
tools/lib/ctype.c
tools/lib/hweight.c
tools/lib/rbtree.c
tools/lib/string.c

View File

@ -22,6 +22,7 @@
#include "../../util/pmu.h"
#include "../../util/thread_map.h"
#include "../../util/cs-etm.h"
#include "../../util/util.h"
#include <errno.h>
#include <stdlib.h>

View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd.
#include <linux/compiler.h>
static struct ins_ops *csky__associate_ins_ops(struct arch *arch,
const char *name)
{
struct ins_ops *ops = NULL;
/* catch all kind of jumps */
if (!strcmp(name, "bt") ||
!strcmp(name, "bf") ||
!strcmp(name, "bez") ||
!strcmp(name, "bnez") ||
!strcmp(name, "bnezad") ||
!strcmp(name, "bhsz") ||
!strcmp(name, "bhz") ||
!strcmp(name, "blsz") ||
!strcmp(name, "blz") ||
!strcmp(name, "br") ||
!strcmp(name, "jmpi") ||
!strcmp(name, "jmp"))
ops = &jump_ops;
/* catch function call */
if (!strcmp(name, "bsr") ||
!strcmp(name, "jsri") ||
!strcmp(name, "jsr"))
ops = &call_ops;
/* catch function return */
if (!strcmp(name, "rts"))
ops = &ret_ops;
if (ops)
arch__associate_ins_ops(arch, name, ops);
return ops;
}
static int csky__annotate_init(struct arch *arch, char *cpuid __maybe_unused)
{
arch->initialized = true;
arch->objdump.comment_char = '/';
arch->associate_instruction_ops = csky__associate_ins_ops;
return 0;
}

View File

@ -11,7 +11,7 @@
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <linux/ctype.h>
#include "../../util/header.h"
#include "../../util/util.h"

View File

@ -6,6 +6,7 @@
#include "evlist.h"
#include "evsel.h"
#include "arch-tests.h"
#include "util.h"
#include <signal.h>
#include <sys/mman.h>

View File

@ -25,6 +25,7 @@
#include "../../util/auxtrace.h"
#include "../../util/tsc.h"
#include "../../util/intel-pt.h"
#include "../../util/util.h"
#define KiB(x) ((x) * 1024)
#define MiB(x) ((x) * 1024 * 1024)

View File

@ -3,10 +3,11 @@
#include <linux/string.h>
#include <stdlib.h>
#include "../../util/util.h"
#include "../../util/machine.h"
#include "../../util/map.h"
#include "../../util/symbol.h"
#include "../../util/sane_ctype.h"
#include <linux/ctype.h>
#include <symbol/kallsyms.h>

View File

@ -21,6 +21,7 @@
#include "util/cpumap.h"
#include "util/debug.h"
#include "util/string2.h"
#include <linux/kernel.h>
#include <linux/rbtree.h>
@ -30,7 +31,7 @@
#include <locale.h>
#include <regex.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
static int kmem_slab;
static int kmem_page;

View File

@ -47,7 +47,7 @@
#include <errno.h>
#include <inttypes.h>
#include <regex.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
#include <signal.h>
#include <linux/bitmap.h>
#include <linux/stringify.h>
@ -941,8 +941,7 @@ parse_time_quantum(const struct option *opt, const char *arg,
pr_err("time quantum cannot be 0");
return -1;
}
while (isspace(*end))
end++;
end = skip_spaces(end);
if (*end == 0)
return 0;
if (!strcmp(end, "s")) {

View File

@ -15,6 +15,7 @@
#include "util/thread_map.h"
#include "util/color.h"
#include "util/stat.h"
#include "util/string2.h"
#include "util/callchain.h"
#include "util/time-utils.h"
@ -36,7 +37,7 @@
#include <api/fs/fs.h>
#include <linux/time64.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
#define PR_SET_NAME 15 /* Set process name */
#define MAX_CPUS 4096

View File

@ -49,7 +49,7 @@
#include <unistd.h>
#include <subcmd/pager.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
static char const *script_name;
static char const *generate_script_lang;
@ -2880,7 +2880,7 @@ static int read_script_info(struct script_desc *desc, const char *filename)
return -1;
while (fgets(line, sizeof(line), fp)) {
p = ltrim(line);
p = skip_spaces(line);
if (strlen(p) == 0)
continue;
if (*p != '#')
@ -2889,19 +2889,19 @@ static int read_script_info(struct script_desc *desc, const char *filename)
if (strlen(p) && *p == '!')
continue;
p = ltrim(p);
p = skip_spaces(p);
if (strlen(p) && p[strlen(p) - 1] == '\n')
p[strlen(p) - 1] = '\0';
if (!strncmp(p, "description:", strlen("description:"))) {
p += strlen("description:");
desc->half_liner = strdup(ltrim(p));
desc->half_liner = strdup(skip_spaces(p));
continue;
}
if (!strncmp(p, "args:", strlen("args:"))) {
p += strlen("args:");
desc->args = strdup(ltrim(p));
desc->args = strdup(skip_spaces(p));
continue;
}
}
@ -3008,7 +3008,7 @@ static int check_ev_match(char *dir_name, char *scriptname,
return -1;
while (fgets(line, sizeof(line), fp)) {
p = ltrim(line);
p = skip_spaces(line);
if (*p == '#')
continue;
@ -3018,7 +3018,7 @@ static int check_ev_match(char *dir_name, char *scriptname,
break;
p += 2;
p = ltrim(p);
p = skip_spaces(p);
len = strcspn(p, " \t");
if (!len)
break;

View File

@ -82,7 +82,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
#define DEFAULT_SEPARATOR " "
#define FREEZE_ON_SMI_PATH "devices/cpu/freeze_on_smi"

View File

@ -40,6 +40,7 @@
#include "util/cpumap.h"
#include "util/xyarray.h"
#include "util/sort.h"
#include "util/string2.h"
#include "util/term.h"
#include "util/intlist.h"
#include "util/parse-branch-options.h"
@ -75,7 +76,7 @@
#include <linux/time64.h>
#include <linux/types.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
static volatile int done;
static volatile int resize;

View File

@ -64,7 +64,7 @@
#include <fcntl.h>
#include <sys/sysmacros.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
#ifndef O_CLOEXEC
# define O_CLOEXEC 02000000

View File

@ -105,6 +105,8 @@ check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/ex
check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"'
check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common\(-tools\)*.h>"'
check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"'
check include/linux/ctype.h '-I "isdigit("'
check lib/ctype.c '-I "^EXPORT_SYMBOL" -I "^#include <linux/export.h>" -B'
# diff non-symmetric files
check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl

View File

@ -18,6 +18,7 @@
#include "util/bpf-loader.h"
#include "util/debug.h"
#include "util/event.h"
#include "util/util.h"
#include <api/fs/fs.h>
#include <api/fs/tracing_path.h>
#include <errno.h>

View File

@ -26,7 +26,7 @@ static inline unsigned long long rdclock(void)
}
#ifndef MAX_NR_CPUS
#define MAX_NR_CPUS 1024
#define MAX_NR_CPUS 2048
#endif
extern const char *input_name;

View File

@ -841,7 +841,7 @@ static void create_empty_mapping(const char *output_file)
_Exit(1);
}
fprintf(outfp, "#include \"../../pmu-events/pmu-events.h\"\n");
fprintf(outfp, "#include \"pmu-events/pmu-events.h\"\n");
print_mapping_table_prefix(outfp);
print_mapping_table_suffix(outfp);
fclose(outfp);
@ -1096,7 +1096,7 @@ int main(int argc, char *argv[])
}
/* Include pmu-events.h first */
fprintf(eventsfp, "#include \"../../pmu-events/pmu-events.h\"\n");
fprintf(eventsfp, "#include \"pmu-events/pmu-events.h\"\n");
/*
* The mapfile allows multiple CPUids to point to the same JSON file,

View File

@ -447,6 +447,38 @@ if perf_db_export_calls:
'insn_count bigint,'
'cyc_count bigint)')
do_query(query, 'CREATE TABLE ptwrite ('
'id bigint NOT NULL,'
'payload bigint,'
'exact_ip boolean)')
do_query(query, 'CREATE TABLE cbr ('
'id bigint NOT NULL,'
'cbr integer,'
'mhz integer,'
'percent integer)')
do_query(query, 'CREATE TABLE mwait ('
'id bigint NOT NULL,'
'hints integer,'
'extensions integer)')
do_query(query, 'CREATE TABLE pwre ('
'id bigint NOT NULL,'
'cstate integer,'
'subcstate integer,'
'hw boolean)')
do_query(query, 'CREATE TABLE exstop ('
'id bigint NOT NULL,'
'exact_ip boolean)')
do_query(query, 'CREATE TABLE pwrx ('
'id bigint NOT NULL,'
'deepest_cstate integer,'
'last_cstate integer,'
'wake_reason integer)')
do_query(query, 'CREATE VIEW machines_view AS '
'SELECT '
'id,'
@ -561,6 +593,104 @@ do_query(query, 'CREATE VIEW samples_view AS '
'CASE WHEN cyc_count=0 THEN CAST(0 AS NUMERIC(20, 2)) ELSE CAST((CAST(insn_count AS FLOAT) / cyc_count) AS NUMERIC(20, 2)) END AS IPC'
' FROM samples')
do_query(query, 'CREATE VIEW ptwrite_view AS '
'SELECT '
'ptwrite.id,'
'time,'
'cpu,'
'to_hex(payload) AS payload_hex,'
'CASE WHEN exact_ip=FALSE THEN \'False\' ELSE \'True\' END AS exact_ip'
' FROM ptwrite'
' INNER JOIN samples ON samples.id = ptwrite.id')
do_query(query, 'CREATE VIEW cbr_view AS '
'SELECT '
'cbr.id,'
'time,'
'cpu,'
'cbr,'
'mhz,'
'percent'
' FROM cbr'
' INNER JOIN samples ON samples.id = cbr.id')
do_query(query, 'CREATE VIEW mwait_view AS '
'SELECT '
'mwait.id,'
'time,'
'cpu,'
'to_hex(hints) AS hints_hex,'
'to_hex(extensions) AS extensions_hex'
' FROM mwait'
' INNER JOIN samples ON samples.id = mwait.id')
do_query(query, 'CREATE VIEW pwre_view AS '
'SELECT '
'pwre.id,'
'time,'
'cpu,'
'cstate,'
'subcstate,'
'CASE WHEN hw=FALSE THEN \'False\' ELSE \'True\' END AS hw'
' FROM pwre'
' INNER JOIN samples ON samples.id = pwre.id')
do_query(query, 'CREATE VIEW exstop_view AS '
'SELECT '
'exstop.id,'
'time,'
'cpu,'
'CASE WHEN exact_ip=FALSE THEN \'False\' ELSE \'True\' END AS exact_ip'
' FROM exstop'
' INNER JOIN samples ON samples.id = exstop.id')
do_query(query, 'CREATE VIEW pwrx_view AS '
'SELECT '
'pwrx.id,'
'time,'
'cpu,'
'deepest_cstate,'
'last_cstate,'
'CASE WHEN wake_reason=1 THEN \'Interrupt\''
' WHEN wake_reason=2 THEN \'Timer Deadline\''
' WHEN wake_reason=4 THEN \'Monitored Address\''
' WHEN wake_reason=8 THEN \'HW\''
' ELSE CAST ( wake_reason AS VARCHAR(2) )'
'END AS wake_reason'
' FROM pwrx'
' INNER JOIN samples ON samples.id = pwrx.id')
do_query(query, 'CREATE VIEW power_events_view AS '
'SELECT '
'samples.id,'
'samples.time,'
'samples.cpu,'
'selected_events.name AS event,'
'FORMAT(\'%6s\', cbr.cbr) AS cbr,'
'FORMAT(\'%6s\', cbr.mhz) AS MHz,'
'FORMAT(\'%5s\', cbr.percent) AS percent,'
'to_hex(mwait.hints) AS hints_hex,'
'to_hex(mwait.extensions) AS extensions_hex,'
'FORMAT(\'%3s\', pwre.cstate) AS cstate,'
'FORMAT(\'%3s\', pwre.subcstate) AS subcstate,'
'CASE WHEN pwre.hw=FALSE THEN \'False\' WHEN pwre.hw=TRUE THEN \'True\' ELSE NULL END AS hw,'
'CASE WHEN exstop.exact_ip=FALSE THEN \'False\' WHEN exstop.exact_ip=TRUE THEN \'True\' ELSE NULL END AS exact_ip,'
'FORMAT(\'%3s\', pwrx.deepest_cstate) AS deepest_cstate,'
'FORMAT(\'%3s\', pwrx.last_cstate) AS last_cstate,'
'CASE WHEN pwrx.wake_reason=1 THEN \'Interrupt\''
' WHEN pwrx.wake_reason=2 THEN \'Timer Deadline\''
' WHEN pwrx.wake_reason=4 THEN \'Monitored Address\''
' WHEN pwrx.wake_reason=8 THEN \'HW\''
' ELSE FORMAT(\'%2s\', pwrx.wake_reason)'
'END AS wake_reason'
' FROM cbr'
' FULL JOIN mwait ON mwait.id = cbr.id'
' FULL JOIN pwre ON pwre.id = cbr.id'
' FULL JOIN exstop ON exstop.id = cbr.id'
' FULL JOIN pwrx ON pwrx.id = cbr.id'
' INNER JOIN samples ON samples.id = coalesce(cbr.id, mwait.id, pwre.id, exstop.id, pwrx.id)'
' INNER JOIN selected_events ON selected_events.id = samples.evsel_id'
' ORDER BY samples.id')
file_header = struct.pack("!11sii", b"PGCOPY\n\377\r\n\0", 0, 0)
file_trailer = b"\377\377"
@ -620,6 +750,12 @@ if perf_db_export_calls or perf_db_export_callchains:
call_path_file = open_output_file("call_path_table.bin")
if perf_db_export_calls:
call_file = open_output_file("call_table.bin")
ptwrite_file = open_output_file("ptwrite_table.bin")
cbr_file = open_output_file("cbr_table.bin")
mwait_file = open_output_file("mwait_table.bin")
pwre_file = open_output_file("pwre_table.bin")
exstop_file = open_output_file("exstop_table.bin")
pwrx_file = open_output_file("pwrx_table.bin")
def trace_begin():
printdate("Writing to intermediate files...")
@ -637,6 +773,16 @@ def trace_begin():
unhandled_count = 0
def is_table_empty(table_name):
do_query(query, 'SELECT * FROM ' + table_name + ' LIMIT 1');
if query.next():
return False
return True
def drop(table_name):
do_query(query, 'DROP VIEW ' + table_name + '_view');
do_query(query, 'DROP TABLE ' + table_name);
def trace_end():
printdate("Copying to database...")
copy_output_file(evsel_file, "selected_events")
@ -652,6 +798,12 @@ def trace_end():
copy_output_file(call_path_file, "call_paths")
if perf_db_export_calls:
copy_output_file(call_file, "calls")
copy_output_file(ptwrite_file, "ptwrite")
copy_output_file(cbr_file, "cbr")
copy_output_file(mwait_file, "mwait")
copy_output_file(pwre_file, "pwre")
copy_output_file(exstop_file, "exstop")
copy_output_file(pwrx_file, "pwrx")
printdate("Removing intermediate files...")
remove_output_file(evsel_file)
@ -667,6 +819,12 @@ def trace_end():
remove_output_file(call_path_file)
if perf_db_export_calls:
remove_output_file(call_file)
remove_output_file(ptwrite_file)
remove_output_file(cbr_file)
remove_output_file(mwait_file)
remove_output_file(pwre_file)
remove_output_file(exstop_file)
remove_output_file(pwrx_file)
os.rmdir(output_dir_name)
printdate("Adding primary keys")
do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
@ -682,6 +840,12 @@ def trace_end():
do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
if perf_db_export_calls:
do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE ptwrite ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE cbr ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE mwait ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE pwre ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE exstop ADD PRIMARY KEY (id)')
do_query(query, 'ALTER TABLE pwrx ADD PRIMARY KEY (id)')
printdate("Adding foreign keys")
do_query(query, 'ALTER TABLE threads '
@ -717,6 +881,30 @@ def trace_end():
'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
do_query(query, 'ALTER TABLE ptwrite '
'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
do_query(query, 'ALTER TABLE cbr '
'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
do_query(query, 'ALTER TABLE mwait '
'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
do_query(query, 'ALTER TABLE pwre '
'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
do_query(query, 'ALTER TABLE exstop '
'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
do_query(query, 'ALTER TABLE pwrx '
'ADD CONSTRAINT idfk FOREIGN KEY (id) REFERENCES samples (id)')
printdate("Dropping unused tables")
if is_table_empty("ptwrite"):
drop("ptwrite")
if is_table_empty("mwait") and is_table_empty("pwre") and is_table_empty("exstop") and is_table_empty("pwrx"):
drop("mwait")
drop("pwre")
drop("exstop")
drop("pwrx")
do_query(query, 'DROP VIEW power_events_view');
if is_table_empty("cbr"):
drop("cbr")
if (unhandled_count):
printdate("Warning: ", unhandled_count, " unhandled events")
@ -800,3 +988,66 @@ def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return
fmt = "!hiqiqiqiqiqiqiqiqiqiqiiiqiqiq"
value = struct.pack(fmt, 14, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags, 8, parent_id, 8, insn_cnt, 8, cyc_cnt)
call_file.write(value)
def ptwrite(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
flags = data[0]
payload = data[1]
exact_ip = flags & 1
value = struct.pack("!hiqiqiB", 3, 8, id, 8, payload, 1, exact_ip)
ptwrite_file.write(value)
def cbr(id, raw_buf):
data = struct.unpack_from("<BBBBII", raw_buf)
cbr = data[0]
MHz = (data[4] + 500) / 1000
percent = ((cbr * 1000 / data[2]) + 5) / 10
value = struct.pack("!hiqiiiiii", 4, 8, id, 4, cbr, 4, MHz, 4, percent)
cbr_file.write(value)
def mwait(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
payload = data[1]
hints = payload & 0xff
extensions = (payload >> 32) & 0x3
value = struct.pack("!hiqiiii", 3, 8, id, 4, hints, 4, extensions)
mwait_file.write(value)
def pwre(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
payload = data[1]
hw = (payload >> 7) & 1
cstate = (payload >> 12) & 0xf
subcstate = (payload >> 8) & 0xf
value = struct.pack("!hiqiiiiiB", 4, 8, id, 4, cstate, 4, subcstate, 1, hw)
pwre_file.write(value)
def exstop(id, raw_buf):
data = struct.unpack_from("<I", raw_buf)
flags = data[0]
exact_ip = flags & 1
value = struct.pack("!hiqiB", 2, 8, id, 1, exact_ip)
exstop_file.write(value)
def pwrx(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
payload = data[1]
deepest_cstate = payload & 0xf
last_cstate = (payload >> 4) & 0xf
wake_reason = (payload >> 8) & 0xf
value = struct.pack("!hiqiiiiii", 4, 8, id, 4, deepest_cstate, 4, last_cstate, 4, wake_reason)
pwrx_file.write(value)
def synth_data(id, config, raw_buf, *x):
if config == 0:
ptwrite(id, raw_buf)
elif config == 1:
mwait(id, raw_buf)
elif config == 2:
pwre(id, raw_buf)
elif config == 3:
exstop(id, raw_buf)
elif config == 4:
pwrx(id, raw_buf)
elif config == 5:
cbr(id, raw_buf)

View File

@ -271,6 +271,38 @@ if perf_db_export_calls:
'insn_count bigint,'
'cyc_count bigint)')
do_query(query, 'CREATE TABLE ptwrite ('
'id integer NOT NULL PRIMARY KEY,'
'payload bigint,'
'exact_ip integer)')
do_query(query, 'CREATE TABLE cbr ('
'id integer NOT NULL PRIMARY KEY,'
'cbr integer,'
'mhz integer,'
'percent integer)')
do_query(query, 'CREATE TABLE mwait ('
'id integer NOT NULL PRIMARY KEY,'
'hints integer,'
'extensions integer)')
do_query(query, 'CREATE TABLE pwre ('
'id integer NOT NULL PRIMARY KEY,'
'cstate integer,'
'subcstate integer,'
'hw integer)')
do_query(query, 'CREATE TABLE exstop ('
'id integer NOT NULL PRIMARY KEY,'
'exact_ip integer)')
do_query(query, 'CREATE TABLE pwrx ('
'id integer NOT NULL PRIMARY KEY,'
'deepest_cstate integer,'
'last_cstate integer,'
'wake_reason integer)')
# printf was added to sqlite in version 3.8.3
sqlite_has_printf = False
try:
@ -399,6 +431,102 @@ do_query(query, 'CREATE VIEW samples_view AS '
'CASE WHEN cyc_count=0 THEN CAST(0 AS FLOAT) ELSE ROUND(CAST(insn_count AS FLOAT) / cyc_count, 2) END AS IPC'
' FROM samples')
do_query(query, 'CREATE VIEW ptwrite_view AS '
'SELECT '
'ptwrite.id,'
'time,'
'cpu,'
+ emit_to_hex('payload') + ' AS payload_hex,'
'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
' FROM ptwrite'
' INNER JOIN samples ON samples.id = ptwrite.id')
do_query(query, 'CREATE VIEW cbr_view AS '
'SELECT '
'cbr.id,'
'time,'
'cpu,'
'cbr,'
'mhz,'
'percent'
' FROM cbr'
' INNER JOIN samples ON samples.id = cbr.id')
do_query(query, 'CREATE VIEW mwait_view AS '
'SELECT '
'mwait.id,'
'time,'
'cpu,'
+ emit_to_hex('hints') + ' AS hints_hex,'
+ emit_to_hex('extensions') + ' AS extensions_hex'
' FROM mwait'
' INNER JOIN samples ON samples.id = mwait.id')
do_query(query, 'CREATE VIEW pwre_view AS '
'SELECT '
'pwre.id,'
'time,'
'cpu,'
'cstate,'
'subcstate,'
'CASE WHEN hw=0 THEN \'False\' ELSE \'True\' END AS hw'
' FROM pwre'
' INNER JOIN samples ON samples.id = pwre.id')
do_query(query, 'CREATE VIEW exstop_view AS '
'SELECT '
'exstop.id,'
'time,'
'cpu,'
'CASE WHEN exact_ip=0 THEN \'False\' ELSE \'True\' END AS exact_ip'
' FROM exstop'
' INNER JOIN samples ON samples.id = exstop.id')
do_query(query, 'CREATE VIEW pwrx_view AS '
'SELECT '
'pwrx.id,'
'time,'
'cpu,'
'deepest_cstate,'
'last_cstate,'
'CASE WHEN wake_reason=1 THEN \'Interrupt\''
' WHEN wake_reason=2 THEN \'Timer Deadline\''
' WHEN wake_reason=4 THEN \'Monitored Address\''
' WHEN wake_reason=8 THEN \'HW\''
' ELSE wake_reason '
'END AS wake_reason'
' FROM pwrx'
' INNER JOIN samples ON samples.id = pwrx.id')
do_query(query, 'CREATE VIEW power_events_view AS '
'SELECT '
'samples.id,'
'time,'
'cpu,'
'selected_events.name AS event,'
'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT cbr FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS cbr,'
'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT mhz FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS mhz,'
'CASE WHEN selected_events.name=\'cbr\' THEN (SELECT percent FROM cbr WHERE cbr.id = samples.id) ELSE "" END AS percent,'
'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('hints') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS hints_hex,'
'CASE WHEN selected_events.name=\'mwait\' THEN (SELECT ' + emit_to_hex('extensions') + ' FROM mwait WHERE mwait.id = samples.id) ELSE "" END AS extensions_hex,'
'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT cstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS cstate,'
'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT subcstate FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS subcstate,'
'CASE WHEN selected_events.name=\'pwre\' THEN (SELECT hw FROM pwre WHERE pwre.id = samples.id) ELSE "" END AS hw,'
'CASE WHEN selected_events.name=\'exstop\' THEN (SELECT exact_ip FROM exstop WHERE exstop.id = samples.id) ELSE "" END AS exact_ip,'
'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT deepest_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS deepest_cstate,'
'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT last_cstate FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS last_cstate,'
'CASE WHEN selected_events.name=\'pwrx\' THEN (SELECT '
'CASE WHEN wake_reason=1 THEN \'Interrupt\''
' WHEN wake_reason=2 THEN \'Timer Deadline\''
' WHEN wake_reason=4 THEN \'Monitored Address\''
' WHEN wake_reason=8 THEN \'HW\''
' ELSE wake_reason '
'END'
' FROM pwrx WHERE pwrx.id = samples.id) ELSE "" END AS wake_reason'
' FROM samples'
' INNER JOIN selected_events ON selected_events.id = evsel_id'
' WHERE selected_events.name IN (\'cbr\',\'mwait\',\'exstop\',\'pwre\',\'pwrx\')')
do_query(query, 'END TRANSACTION')
evsel_query = QSqlQuery(db)
@ -428,6 +556,18 @@ if perf_db_export_calls or perf_db_export_callchains:
if perf_db_export_calls:
call_query = QSqlQuery(db)
call_query.prepare("INSERT INTO calls VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
ptwrite_query = QSqlQuery(db)
ptwrite_query.prepare("INSERT INTO ptwrite VALUES (?, ?, ?)")
cbr_query = QSqlQuery(db)
cbr_query.prepare("INSERT INTO cbr VALUES (?, ?, ?, ?)")
mwait_query = QSqlQuery(db)
mwait_query.prepare("INSERT INTO mwait VALUES (?, ?, ?)")
pwre_query = QSqlQuery(db)
pwre_query.prepare("INSERT INTO pwre VALUES (?, ?, ?, ?)")
exstop_query = QSqlQuery(db)
exstop_query.prepare("INSERT INTO exstop VALUES (?, ?)")
pwrx_query = QSqlQuery(db)
pwrx_query.prepare("INSERT INTO pwrx VALUES (?, ?, ?, ?)")
def trace_begin():
printdate("Writing records...")
@ -446,6 +586,16 @@ def trace_begin():
unhandled_count = 0
def is_table_empty(table_name):
do_query(query, 'SELECT * FROM ' + table_name + ' LIMIT 1');
if query.next():
return False
return True
def drop(table_name):
do_query(query, 'DROP VIEW ' + table_name + '_view');
do_query(query, 'DROP TABLE ' + table_name);
def trace_end():
do_query(query, 'END TRANSACTION')
@ -454,6 +604,18 @@ def trace_end():
do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
do_query(query, 'CREATE INDEX pid_idx ON calls (parent_id)')
printdate("Dropping unused tables")
if is_table_empty("ptwrite"):
drop("ptwrite")
if is_table_empty("mwait") and is_table_empty("pwre") and is_table_empty("exstop") and is_table_empty("pwrx"):
drop("mwait")
drop("pwre")
drop("exstop")
drop("pwrx")
do_query(query, 'DROP VIEW power_events_view');
if is_table_empty("cbr"):
drop("cbr")
if (unhandled_count):
printdate("Warning: ", unhandled_count, " unhandled events")
printdate("Done")
@ -509,3 +671,80 @@ def call_path_table(*x):
def call_return_table(*x):
bind_exec(call_query, 14, x)
def ptwrite(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
flags = data[0]
payload = data[1]
exact_ip = flags & 1
ptwrite_query.addBindValue(str(id))
ptwrite_query.addBindValue(str(payload))
ptwrite_query.addBindValue(str(exact_ip))
do_query_(ptwrite_query)
def cbr(id, raw_buf):
data = struct.unpack_from("<BBBBII", raw_buf)
cbr = data[0]
MHz = (data[4] + 500) / 1000
percent = ((cbr * 1000 / data[2]) + 5) / 10
cbr_query.addBindValue(str(id))
cbr_query.addBindValue(str(cbr))
cbr_query.addBindValue(str(MHz))
cbr_query.addBindValue(str(percent))
do_query_(cbr_query)
def mwait(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
payload = data[1]
hints = payload & 0xff
extensions = (payload >> 32) & 0x3
mwait_query.addBindValue(str(id))
mwait_query.addBindValue(str(hints))
mwait_query.addBindValue(str(extensions))
do_query_(mwait_query)
def pwre(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
payload = data[1]
hw = (payload >> 7) & 1
cstate = (payload >> 12) & 0xf
subcstate = (payload >> 8) & 0xf
pwre_query.addBindValue(str(id))
pwre_query.addBindValue(str(cstate))
pwre_query.addBindValue(str(subcstate))
pwre_query.addBindValue(str(hw))
do_query_(pwre_query)
def exstop(id, raw_buf):
data = struct.unpack_from("<I", raw_buf)
flags = data[0]
exact_ip = flags & 1
exstop_query.addBindValue(str(id))
exstop_query.addBindValue(str(exact_ip))
do_query_(exstop_query)
def pwrx(id, raw_buf):
data = struct.unpack_from("<IQ", raw_buf)
payload = data[1]
deepest_cstate = payload & 0xf
last_cstate = (payload >> 4) & 0xf
wake_reason = (payload >> 8) & 0xf
pwrx_query.addBindValue(str(id))
pwrx_query.addBindValue(str(deepest_cstate))
pwrx_query.addBindValue(str(last_cstate))
pwrx_query.addBindValue(str(wake_reason))
do_query_(pwrx_query)
def synth_data(id, config, raw_buf, *x):
if config == 0:
ptwrite(id, raw_buf)
elif config == 1:
mwait(id, raw_buf)
elif config == 2:
pwre(id, raw_buf)
elif config == 3:
exstop(id, raw_buf)
elif config == 4:
pwrx(id, raw_buf)
elif config == 5:
cbr(id, raw_buf)

View File

@ -22,6 +22,7 @@
#include "string2.h"
#include "symbol.h"
#include <linux/kernel.h>
#include <linux/string.h>
#include <subcmd/exec-cmd.h>
static bool dont_fork;
@ -438,7 +439,7 @@ static const char *shell_test__description(char *description, size_t size,
description = fgets(description, size, fp);
fclose(fp);
return description ? trim(description + 1) : NULL;
return description ? strim(description + 1) : NULL;
}
#define for_each_shell_test(dir, base, ent) \

View File

@ -22,7 +22,7 @@
#include "tests.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#define BUFSZ 1024
#define READLEN 128

View File

@ -16,7 +16,7 @@
#include "helpline.h"
#include "keysyms.h"
#include "../color.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
static int ui_browser__percent_color(struct ui_browser *browser,
double percent, bool current)
@ -594,7 +594,7 @@ static int ui_browser__color_config(const char *var, const char *value,
break;
*bg = '\0';
bg = ltrim(++bg);
bg = skip_spaces(bg + 1);
ui_browser__colorsets[i].bg = bg;
ui_browser__colorsets[i].fg = fg;
return 0;

View File

@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string.h>
#include <linux/rbtree.h>
#include <linux/string.h>
#include <sys/ttydefaults.h>
#include <linux/time64.h>
@ -33,7 +34,7 @@
#include "units.h"
#include "time-utils.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
extern void hist_browser__init_hpp(void);
@ -1470,7 +1471,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
int i = 0;
width -= fmt->entry(fmt, &hpp, entry);
ui_browser__printf(&browser->b, "%s", ltrim(s));
ui_browser__printf(&browser->b, "%s", skip_spaces(s));
while (isspace(s[i++]))
width++;
@ -1686,7 +1687,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
dummy_hpp.buf[ret] = '\0';
start = trim(dummy_hpp.buf);
start = strim(dummy_hpp.buf);
ret = strlen(start);
if (start != dummy_hpp.buf)
@ -2070,7 +2071,8 @@ static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
advance_hpp(&hpp, ret);
}
printed += fprintf(fp, "%s\n", rtrim(s));
strim(s);
printed += fprintf(fp, "%s\n", s);
if (he->leaf && folded_sign == '-') {
printed += hist_browser__fprintf_callchain(browser, he, fp,

View File

@ -13,7 +13,7 @@
#include "../keysyms.h"
#include "map.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
struct map_browser {
struct ui_browser b;

View File

@ -9,6 +9,7 @@
#include "../string2.h"
#include "gtk.h"
#include <signal.h>
#include <linux/string.h>
#define MAX_COLUMNS 32
@ -459,7 +460,7 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
advance_hpp(hpp, ret + 2);
}
gtk_tree_store_set(store, &iter, col_idx, ltrim(rtrim(bf)), -1);
gtk_tree_store_set(store, &iter, col_idx, strim(bf), -1);
if (!he->leaf) {
hpp->buf = bf;
@ -555,7 +556,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
first_col = false;
fmt->header(fmt, &hpp, hists, 0, NULL);
strcat(buf, ltrim(rtrim(hpp.buf)));
strcat(buf, strim(hpp.buf));
}
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include "../cache.h"
#include "../util/cache.h"
#include "progress.h"
static void null_progress__update(struct ui_progress *p __maybe_unused)

View File

@ -13,7 +13,7 @@
#include "../../util/srcline.h"
#include "../../util/string2.h"
#include "../../util/thread.h"
#include "../../util/sane_ctype.h"
#include <linux/ctype.h>
static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
{
@ -516,7 +516,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
* dynamic entries are right-aligned but we want left-aligned
* in the hierarchy mode
*/
printed += fprintf(fp, "%s%s", sep ?: " ", ltrim(buf));
printed += fprintf(fp, "%s%s", sep ?: " ", skip_spaces(buf));
}
printed += putc('\n', fp);
@ -566,10 +566,14 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
static int print_hierarchy_indent(const char *sep, int indent,
const char *line, FILE *fp)
{
int width;
if (sep != NULL || indent < 2)
return 0;
return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line);
width = (indent - 2) * HIERARCHY_INDENT;
return fprintf(fp, "%-*.*s", width, width, line);
}
static int hists__fprintf_hierarchy_headers(struct hists *hists,
@ -587,7 +591,7 @@ static int hists__fprintf_hierarchy_headers(struct hists *hists,
indent = hists->nr_hpp_node;
/* preserve max indent depth for column headers */
print_hierarchy_indent(sep, indent, spaces, fp);
print_hierarchy_indent(sep, indent, " ", fp);
/* the first hpp_list_node is for overhead columns */
fmt_node = list_first_entry(&hists->hpp_formats,
@ -616,7 +620,7 @@ static int hists__fprintf_hierarchy_headers(struct hists *hists,
fmt->header(fmt, hpp, hists, 0, NULL);
header_width += fprintf(fp, "%s", trim(hpp->buf));
header_width += fprintf(fp, "%s", strim(hpp->buf));
}
}
@ -816,7 +820,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
int depth = hists->nr_hpp_node + h->depth + 1;
print_hierarchy_indent(sep, depth, spaces, fp);
print_hierarchy_indent(sep, depth, " ", fp);
fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
if (max_rows && ++nr_rows >= max_rows)

View File

@ -20,6 +20,7 @@ perf-y += parse-events.o
perf-y += perf_regs.o
perf-y += path.o
perf-y += print_binary.o
perf-y += argv_split.o
perf-y += rbtree.o
perf-y += libstring.o
perf-y += bitmap.o
@ -209,10 +210,18 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
$(OUTPUT)util/argv_split.o: ../lib/argv_split.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
$(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
$(OUTPUT)util/ctype.o: ../lib/ctype.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
$(OUTPUT)util/find_bit.o: ../lib/find_bit.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)

View File

@ -35,6 +35,7 @@
#include <pthread.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <bpf/libbpf.h>
/* FIXME: For the HE_COLORSET */
@ -49,7 +50,7 @@
#define DARROW_CHAR ((unsigned char)'.')
#define UARROW_CHAR ((unsigned char)'-')
#include "sane_ctype.h"
#include <linux/ctype.h>
struct annotation_options annotation__default_options = {
.use_offset = true,
@ -144,6 +145,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i
#include "arch/arc/annotate/instructions.c"
#include "arch/arm/annotate/instructions.c"
#include "arch/arm64/annotate/instructions.c"
#include "arch/csky/annotate/instructions.c"
#include "arch/x86/annotate/instructions.c"
#include "arch/powerpc/annotate/instructions.c"
#include "arch/s390/annotate/instructions.c"
@ -162,6 +164,10 @@ static struct arch architectures[] = {
.name = "arm64",
.init = arm64__annotate_init,
},
{
.name = "csky",
.init = csky__annotate_init,
},
{
.name = "x86",
.init = x86__annotate_init,
@ -557,7 +563,7 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_sy
if (comment == NULL)
return 0;
comment = ltrim(comment);
comment = skip_spaces(comment);
comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name);
comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
@ -602,7 +608,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops
if (comment == NULL)
return 0;
comment = ltrim(comment);
comment = skip_spaces(comment);
comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
return 0;
@ -1098,7 +1104,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, str
static int disasm_line__parse(char *line, const char **namep, char **rawp)
{
char tmp, *name = ltrim(line);
char tmp, *name = skip_spaces(line);
if (name[0] == '\0')
return -1;
@ -1116,7 +1122,7 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp)
goto out_free_name;
(*rawp)[0] = tmp;
*rawp = ltrim(*rawp);
*rawp = skip_spaces(*rawp);
return 0;
@ -1495,7 +1501,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
return -1;
line_ip = -1;
parsed_line = rtrim(line);
parsed_line = strim(line);
/* /filename:linenr ? Save line number and ignore. */
if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
@ -1503,7 +1509,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
return 0;
}
tmp = ltrim(parsed_line);
tmp = skip_spaces(parsed_line);
if (*tmp) {
/*
* Parse hexa addresses followed by ':'

View File

@ -51,7 +51,7 @@
#include "arm-spe.h"
#include "s390-cpumsf.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#include "symbol/kallsyms.h"
static bool auxtrace__dont_decode(struct perf_session *session)

View File

@ -29,7 +29,7 @@
#include "probe-file.h"
#include "strlist.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
static bool no_buildid_cache;

View File

@ -24,7 +24,7 @@
#include <unistd.h>
#include <linux/string.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
#define MAXNAME (256)

View File

@ -10,7 +10,7 @@
#include <linux/bitmap.h>
#include "asm/bug.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
static int max_cpu_num;
static int max_present_cpu_num;

View File

@ -1,49 +0,0 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Sane locale-independent, ASCII ctype.
*
* No surprises, and works with signed and unsigned chars.
*/
#include "sane_ctype.h"
enum {
S = GIT_SPACE,
A = GIT_ALPHA,
D = GIT_DIGIT,
G = GIT_GLOB_SPECIAL, /* *, ?, [, \\ */
R = GIT_REGEX_SPECIAL, /* $, (, ), +, ., ^, {, | * */
P = GIT_PRINT_EXTRA, /* printable - alpha - digit - glob - regex */
PS = GIT_SPACE | GIT_PRINT_EXTRA,
};
unsigned char sane_ctype[256] = {
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0, 0, 0, 0, 0, 0, 0, 0, 0, S, S, 0, 0, S, 0, 0, /* 0.. 15 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16.. 31 */
PS,P, P, P, R, P, P, P, R, R, G, R, P, P, R, P, /* 32.. 47 */
D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, G, /* 48.. 63 */
P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 64.. 79 */
A, A, A, A, A, A, A, A, A, A, A, G, G, P, R, P, /* 80.. 95 */
P, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, /* 96..111 */
A, A, A, A, A, A, A, A, A, A, A, R, R, P, P, 0, /* 112..127 */
/* Nothing in the 128.. range */
};
const char *graph_line =
"_____________________________________________________________________"
"_____________________________________________________________________"
"_____________________________________________________________________";
const char *graph_dotted_line =
"---------------------------------------------------------------------"
"---------------------------------------------------------------------"
"---------------------------------------------------------------------";
const char *spaces =
" "
" "
" ";
const char *dots =
"....................................................................."
"....................................................................."
".....................................................................";

View File

@ -29,7 +29,7 @@
#include "evsel.h"
#include "machine.h"
#include "config.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#define pr_N(n, fmt, ...) \
eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)

View File

@ -21,7 +21,7 @@
#include "util.h"
#include "target.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
int verbose;
bool dump_trace = false, quiet = false;

View File

@ -8,7 +8,7 @@
#include "demangle-java.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
enum {
MODE_PREFIX = 0,

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <asm/bug.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
@ -394,7 +395,7 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
return -ENOMEM;
}
strxfrchar(m->name, '-', '_');
strreplace(m->name, '-', '_');
}
return 0;

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "cpumap.h"
#include "env.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#include "util.h"
#include "bpf-event.h"
#include <errno.h>

View File

@ -20,7 +20,7 @@
#include "strlist.h"
#include "thread.h"
#include "thread_map.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#include "map.h"
#include "symbol.h"
#include "symbol/kallsyms.h"
@ -158,9 +158,7 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
if (name) {
char *nl;
name += 5; /* strlen("Name:") */
name = ltrim(name);
name = skip_spaces(name + 5); /* strlen("Name:") */
nl = strchr(name, '\n');
if (nl)
*nl = '\0';

View File

@ -35,10 +35,11 @@
#include "debug.h"
#include "trace-event.h"
#include "stat.h"
#include "string2.h"
#include "memswap.h"
#include "util/parse-branch-options.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
struct perf_missing_features perf_missing_features;

View File

@ -13,6 +13,7 @@
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/stringify.h>
#include <sys/stat.h>
#include <sys/utsname.h>
@ -43,7 +44,7 @@
#include "cputopo.h"
#include "bpf-event.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
/*
* magic2 = "PERFILE2"
@ -416,10 +417,8 @@ static int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc)
while (*p) {
if (isspace(*p)) {
char *r = p + 1;
char *q = r;
char *q = skip_spaces(r);
*p = ' ';
while (*q && isspace(*q))
q++;
if (q != (p+1))
while ((*r++ = *q++));
}
@ -1049,7 +1048,7 @@ static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 lev
return -1;
cache->type[len] = 0;
cache->type = rtrim(cache->type);
cache->type = strim(cache->type);
scnprintf(file, PATH_MAX, "%s/size", path);
if (sysfs__read_str(file, &cache->size, &len)) {
@ -1058,7 +1057,7 @@ static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 lev
}
cache->size[len] = 0;
cache->size = rtrim(cache->size);
cache->size = strim(cache->size);
scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
if (sysfs__read_str(file, &cache->map, &len)) {
@ -1068,7 +1067,7 @@ static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 lev
}
cache->map[len] = 0;
cache->map = rtrim(cache->map);
cache->map = strim(cache->map);
return 0;
}
@ -1121,7 +1120,7 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp)
return 0;
}
#define MAX_CACHES 2000
#define MAX_CACHES (MAX_NR_CPUS * 4)
static int write_cache(struct feat_fd *ff,
struct perf_evlist *evlist __maybe_unused)

View File

@ -1 +0,0 @@
#include "../util.h"

View File

@ -1975,6 +1975,13 @@ next:
goto next;
if (err)
return err;
/*
* PSB+ CBR will not have changed but cater for the
* possibility of another CBR change that gets caught up
* in the PSB+.
*/
if (decoder->cbr != decoder->cbr_seen)
return 0;
break;
case INTEL_PT_PIP:
@ -2015,16 +2022,8 @@ next:
case INTEL_PT_CBR:
intel_pt_calc_cbr(decoder);
if (!decoder->branch_enable &&
decoder->cbr != decoder->cbr_seen) {
decoder->cbr_seen = decoder->cbr;
decoder->state.type = INTEL_PT_CBR_CHG;
decoder->state.from_ip = decoder->ip;
decoder->state.to_ip = 0;
decoder->state.cbr_payload =
decoder->packet.payload;
if (decoder->cbr != decoder->cbr_seen)
return 0;
}
break;
case INTEL_PT_MODE_EXEC:
@ -2626,10 +2625,15 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt;
} else {
decoder->state.err = 0;
if (decoder->cbr != decoder->cbr_seen && decoder->state.type) {
if (decoder->cbr != decoder->cbr_seen) {
decoder->cbr_seen = decoder->cbr;
if (!decoder->state.type) {
decoder->state.from_ip = decoder->ip;
decoder->state.to_ip = 0;
}
decoder->state.type |= INTEL_PT_CBR_CHG;
decoder->state.cbr_payload = decoder->cbr_payload;
decoder->state.cbr = decoder->cbr;
}
if (intel_pt_sample_time(decoder->pkt_state)) {
intel_pt_update_sample_time(decoder);

View File

@ -213,6 +213,7 @@ struct intel_pt_state {
uint64_t pwre_payload;
uint64_t pwrx_payload;
uint64_t cbr_payload;
uint32_t cbr;
uint32_t flags;
enum intel_pt_insn_op insn_op;
int insn_len;

View File

@ -171,6 +171,7 @@ struct intel_pt_queue {
u64 last_in_cyc_cnt;
u64 last_br_insn_cnt;
u64 last_br_cyc_cnt;
unsigned int cbr_seen;
char insn[INTEL_PT_INSN_BUF_SZ];
};
@ -1052,6 +1053,8 @@ static int intel_pt_setup_queue(struct intel_pt *pt,
ptq->cpu = queue->cpu;
ptq->tid = queue->tid;
ptq->cbr_seen = UINT_MAX;
if (pt->sampling_mode && !pt->snapshot_mode &&
pt->timeless_decoding)
ptq->step_through_buffers = true;
@ -1184,6 +1187,17 @@ static inline bool intel_pt_skip_event(struct intel_pt *pt)
pt->num_events++ < pt->synth_opts.initial_skip;
}
/*
* Cannot count CBR as skipped because it won't go away until cbr == cbr_seen.
* Also ensure CBR is first non-skipped event by allowing for 4 more samples
* from this decoder state.
*/
static inline bool intel_pt_skip_cbr_event(struct intel_pt *pt)
{
return pt->synth_opts.initial_skip &&
pt->num_events + 4 < pt->synth_opts.initial_skip;
}
static void intel_pt_prep_a_sample(struct intel_pt_queue *ptq,
union perf_event *event,
struct perf_sample *sample)
@ -1429,9 +1443,11 @@ static int intel_pt_synth_cbr_sample(struct intel_pt_queue *ptq)
struct perf_synth_intel_cbr raw;
u32 flags;
if (intel_pt_skip_event(pt))
if (intel_pt_skip_cbr_event(pt))
return 0;
ptq->cbr_seen = ptq->state->cbr;
intel_pt_prep_p_sample(pt, ptq, event, &sample);
sample.id = ptq->pt->cbr_id;
@ -1868,8 +1884,7 @@ static inline bool intel_pt_is_switch_ip(struct intel_pt_queue *ptq, u64 ip)
}
#define INTEL_PT_PWR_EVT (INTEL_PT_MWAIT_OP | INTEL_PT_PWR_ENTRY | \
INTEL_PT_EX_STOP | INTEL_PT_PWR_EXIT | \
INTEL_PT_CBR_CHG)
INTEL_PT_EX_STOP | INTEL_PT_PWR_EXIT)
static int intel_pt_sample(struct intel_pt_queue *ptq)
{
@ -1901,31 +1916,33 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
return err;
}
if (pt->sample_pwr_events && (state->type & INTEL_PT_PWR_EVT)) {
if (state->type & INTEL_PT_CBR_CHG) {
if (pt->sample_pwr_events) {
if (ptq->state->cbr != ptq->cbr_seen) {
err = intel_pt_synth_cbr_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_MWAIT_OP) {
err = intel_pt_synth_mwait_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_PWR_ENTRY) {
err = intel_pt_synth_pwre_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_EX_STOP) {
err = intel_pt_synth_exstop_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_PWR_EXIT) {
err = intel_pt_synth_pwrx_sample(ptq);
if (err)
return err;
if (state->type & INTEL_PT_PWR_EVT) {
if (state->type & INTEL_PT_MWAIT_OP) {
err = intel_pt_synth_mwait_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_PWR_ENTRY) {
err = intel_pt_synth_pwre_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_EX_STOP) {
err = intel_pt_synth_exstop_sample(ptq);
if (err)
return err;
}
if (state->type & INTEL_PT_PWR_EXIT) {
err = intel_pt_synth_pwrx_sample(ptq);
if (err)
return err;
}
}
}

View File

@ -28,7 +28,7 @@
#include "genelf.h"
#include "../builtin.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
struct jit_buf_desc {
struct perf_data *output;

View File

@ -15,6 +15,7 @@
#include "strlist.h"
#include "thread.h"
#include "vdso.h"
#include "util.h"
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -24,7 +25,7 @@
#include "asm/bug.h"
#include "bpf-event.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#include <symbol/kallsyms.h>
#include <linux/mman.h>

View File

@ -17,7 +17,7 @@
#include "pmu-events/pmu-events.h"
#include "strlist.h"
#include <assert.h>
#include <ctype.h>
#include <linux/ctype.h>
struct metric_event *metricgroup__lookup(struct rblist *metric_events,
struct perf_evsel *evsel,
@ -85,26 +85,49 @@ struct egroup {
const char *metric_expr;
};
static struct perf_evsel *find_evsel(struct perf_evlist *perf_evlist,
const char **ids,
int idnum,
struct perf_evsel **metric_events)
static bool record_evsel(int *ind, struct perf_evsel **start,
int idnum,
struct perf_evsel **metric_events,
struct perf_evsel *ev)
{
metric_events[*ind] = ev;
if (*ind == 0)
*start = ev;
if (++*ind == idnum) {
metric_events[*ind] = NULL;
return true;
}
return false;
}
static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist,
const char **ids,
int idnum,
struct perf_evsel **metric_events)
{
struct perf_evsel *ev, *start = NULL;
int ind = 0;
evlist__for_each_entry (perf_evlist, ev) {
if (ev->collect_stat)
continue;
if (!strcmp(ev->name, ids[ind])) {
metric_events[ind] = ev;
if (ind == 0)
start = ev;
if (++ind == idnum) {
metric_events[ind] = NULL;
if (record_evsel(&ind, &start, idnum,
metric_events, ev))
return start;
}
} else {
/*
* We saw some other event that is not
* in our list of events. Discard
* the whole match and start again.
*/
ind = 0;
start = NULL;
if (!strcmp(ev->name, ids[ind])) {
if (record_evsel(&ind, &start, idnum,
metric_events, ev))
return start;
}
}
}
/*
@ -134,8 +157,8 @@ static int metricgroup__setup_events(struct list_head *groups,
ret = -ENOMEM;
break;
}
evsel = find_evsel(perf_evlist, eg->ids, eg->idnum,
metric_events);
evsel = find_evsel_group(perf_evlist, eg->ids, eg->idnum,
metric_events);
if (!evsel) {
pr_debug("Cannot resolve %s: %s\n",
eg->metric_name, eg->metric_expr);
@ -308,10 +331,9 @@ void metricgroup__print(bool metrics, bool metricgroups, char *filter,
struct mep *me;
char *s;
g = skip_spaces(g);
if (*g == 0)
g = "No_group";
while (isspace(*g))
g++;
if (filter && !strstr(g, filter))
continue;
if (raw)

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/list.h>
#include <linux/compiler.h>
#include <linux/string.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
@ -394,7 +395,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
buf[ret] = 0;
/* Remove trailing newline from sysfs file */
rtrim(buf);
strim(buf);
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
NULL, NULL, NULL);
@ -1339,7 +1340,7 @@ static void wordwrap(char *s, int start, int max, int corr)
break;
s += wlen;
column += n;
s = ltrim(s);
s = skip_spaces(s);
}
}

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "print_binary.h"
#include <linux/log2.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
int binary__fprintf(unsigned char *data, size_t len,
size_t bytes_per_line, binary__fprintf_t printer,

View File

@ -39,7 +39,7 @@
#include "session.h"
#include "string2.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#define PERFPROBE_GROUP "probe"

View File

@ -5,7 +5,7 @@
#include <stdbool.h>
#include "intlist.h"
#include "probe-event.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#define MAX_PROBE_BUFFER 1024
#define MAX_PROBES 128

View File

@ -6,7 +6,7 @@
#
util/python.c
util/ctype.c
../lib/ctype.c
util/evlist.c
util/evsel.c
util/cpumap.c
@ -16,6 +16,7 @@ util/namespaces.c
../lib/bitmap.c
../lib/find_bit.c
../lib/hweight.c
../lib/string.c
../lib/vsprintf.c
util/thread_map.c
util/util.c

View File

@ -12,6 +12,7 @@
#include "print_binary.h"
#include "thread_map.h"
#include "mmap.h"
#include "util.h"
#if PY_MAJOR_VERSION < 3
#define _PyUnicode_FromString(arg) \

View File

@ -1,52 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _PERF_SANE_CTYPE_H
#define _PERF_SANE_CTYPE_H
extern const char *graph_line;
extern const char *graph_dotted_line;
extern const char *spaces;
extern const char *dots;
/* Sane ctype - no locale, and works with signed chars */
#undef isascii
#undef isspace
#undef isdigit
#undef isxdigit
#undef isalpha
#undef isprint
#undef isalnum
#undef islower
#undef isupper
#undef tolower
#undef toupper
extern unsigned char sane_ctype[256];
#define GIT_SPACE 0x01
#define GIT_DIGIT 0x02
#define GIT_ALPHA 0x04
#define GIT_GLOB_SPECIAL 0x08
#define GIT_REGEX_SPECIAL 0x10
#define GIT_PRINT_EXTRA 0x20
#define GIT_PRINT 0x3E
#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
#define isascii(x) (((x) & ~0x7f) == 0)
#define isspace(x) sane_istest(x,GIT_SPACE)
#define isdigit(x) sane_istest(x,GIT_DIGIT)
#define isxdigit(x) \
(sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
#define isalpha(x) sane_istest(x,GIT_ALPHA)
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
#define isprint(x) sane_istest(x,GIT_PRINT)
#define islower(x) (sane_istest(x,GIT_ALPHA) && (x & 0x20))
#define isupper(x) (sane_istest(x,GIT_ALPHA) && !(x & 0x20))
#define tolower(x) sane_case((unsigned char)(x), 0x20)
#define toupper(x) sane_case((unsigned char)(x), 0)
static inline int sane_case(int x, int high)
{
if (sane_istest(x, GIT_ALPHA))
x = (x & ~0x20) | high;
return x;
}
#endif /* _PERF_SANE_CTYPE_H */

View File

@ -112,6 +112,7 @@ struct tables {
PyObject *sample_handler;
PyObject *call_path_handler;
PyObject *call_return_handler;
PyObject *synth_handler;
bool db_export_mode;
};
@ -947,6 +948,12 @@ static int tuple_set_string(PyObject *t, unsigned int pos, const char *s)
return PyTuple_SetItem(t, pos, _PyUnicode_FromString(s));
}
static int tuple_set_bytes(PyObject *t, unsigned int pos, void *bytes,
unsigned int sz)
{
return PyTuple_SetItem(t, pos, _PyBytes_FromStringAndSize(bytes, sz));
}
static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel)
{
struct tables *tables = container_of(dbe, struct tables, dbe);
@ -1105,8 +1112,8 @@ static int python_export_branch_type(struct db_export *dbe, u32 branch_type,
return 0;
}
static int python_export_sample(struct db_export *dbe,
struct export_sample *es)
static void python_export_sample_table(struct db_export *dbe,
struct export_sample *es)
{
struct tables *tables = container_of(dbe, struct tables, dbe);
PyObject *t;
@ -1141,6 +1148,33 @@ static int python_export_sample(struct db_export *dbe,
call_object(tables->sample_handler, t, "sample_table");
Py_DECREF(t);
}
static void python_export_synth(struct db_export *dbe, struct export_sample *es)
{
struct tables *tables = container_of(dbe, struct tables, dbe);
PyObject *t;
t = tuple_new(3);
tuple_set_u64(t, 0, es->db_id);
tuple_set_u64(t, 1, es->evsel->attr.config);
tuple_set_bytes(t, 2, es->sample->raw_data, es->sample->raw_size);
call_object(tables->synth_handler, t, "synth_data");
Py_DECREF(t);
}
static int python_export_sample(struct db_export *dbe,
struct export_sample *es)
{
struct tables *tables = container_of(dbe, struct tables, dbe);
python_export_sample_table(dbe, es);
if (es->evsel->attr.type == PERF_TYPE_SYNTH && tables->synth_handler)
python_export_synth(dbe, es);
return 0;
}
@ -1477,6 +1511,14 @@ static void set_table_handlers(struct tables *tables)
SET_TABLE_HANDLER(sample);
SET_TABLE_HANDLER(call_path);
SET_TABLE_HANDLER(call_return);
/*
* Synthesized events are samples but with architecture-specific data
* stored in sample->raw_data. They are exported via
* python_export_sample() and consequently do not need a separate export
* callback.
*/
tables->synth_handler = get_handler("synth_data");
}
#if PY_MAJOR_VERSION < 3

View File

@ -5,6 +5,7 @@
#include <string.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include "util/dso.h"
#include "util/util.h"
@ -464,7 +465,7 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
char *srcline;
struct symbol *inline_sym;
rtrim(funcname);
strim(funcname);
if (getline(&filename, &filelen, fp) == -1)
goto out;

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <inttypes.h>
#include <linux/string.h>
#include <linux/time64.h>
#include <math.h>
#include "color.h"
@ -10,7 +11,7 @@
#include "thread_map.h"
#include "cpumap.h"
#include "string2.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#include "cgroup.h"
#include <math.h>
#include <api/fs/fs.h>
@ -211,13 +212,11 @@ static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
return;
}
snprintf(buf, sizeof(buf), fmt, val);
ends = vals = ltrim(buf);
ends = vals = skip_spaces(buf);
while (isdigit(*ends) || *ends == '.')
ends++;
*ends = 0;
while (isspace(*unit))
unit++;
fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, unit);
fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, skip_spaces(unit));
}
/* Filter out some columns that don't work well in metrics only mode */
@ -281,7 +280,7 @@ static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused
return;
unit = fixunit(tbuf, os->evsel, unit);
snprintf(buf, sizeof buf, fmt, val);
ends = vals = ltrim(buf);
ends = vals = skip_spaces(buf);
while (isdigit(*ends) || *ends == '.')
ends++;
*ends = 0;
@ -555,7 +554,8 @@ static void collect_all_aliases(struct perf_stat_config *config, struct perf_evs
alias->scale != counter->scale ||
alias->cgrp != counter->cgrp ||
strcmp(alias->unit, counter->unit) ||
perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter))
perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter) ||
!strcmp(alias->pmu_name, counter->pmu_name))
break;
alias->merged_stat = true;
cb(config, alias, data, false);

View File

@ -304,7 +304,7 @@ static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list,
struct perf_evsel *c2;
evlist__for_each_entry (evsel_list, c2) {
if (!strcasecmp(c2->name, name))
if (!strcasecmp(c2->name, name) && !c2->collect_stat)
return c2;
}
return NULL;
@ -343,7 +343,8 @@ void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list)
if (leader) {
/* Search in group */
for_each_group_member (oc, leader) {
if (!strcasecmp(oc->name, metric_names[i])) {
if (!strcasecmp(oc->name, metric_names[i]) &&
!oc->collect_stat) {
found = true;
break;
}
@ -723,6 +724,7 @@ static void generic_metric(struct perf_stat_config *config,
double ratio;
int i;
void *ctxp = out->ctx;
char *n, *pn;
expr__ctx_init(&pctx);
expr__add_id(&pctx, name, avg);
@ -742,7 +744,19 @@ static void generic_metric(struct perf_stat_config *config,
stats = &v->stats;
scale = 1.0;
}
expr__add_id(&pctx, metric_events[i]->name, avg_stats(stats)*scale);
n = strdup(metric_events[i]->name);
if (!n)
return;
/*
* This display code with --no-merge adds [cpu] postfixes.
* These are not supported by the parser. Remove everything
* after the space.
*/
pn = strchr(n, ' ');
if (pn)
*pn = 0;
expr__add_id(&pctx, n, avg_stats(stats)*scale);
}
if (!metric_events[i]) {
const char *p = metric_expr;
@ -759,6 +773,9 @@ static void generic_metric(struct perf_stat_config *config,
(metric_name ? metric_name : name) : "", 0);
} else
print_metric(config, ctxp, NULL, NULL, "", 0);
for (i = 1; i < pctx.num_ids; i++)
free((void *)pctx.ids[i].name);
}
void perf_stat__print_shadow_stats(struct perf_stat_config *config,

View File

@ -4,7 +4,8 @@
#include "strfilter.h"
#include <errno.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
#include <linux/string.h>
/* Operators */
static const char *OP_and = "&"; /* Logical AND */
@ -37,8 +38,7 @@ static const char *get_token(const char *s, const char **e)
{
const char *p;
while (isspace(*s)) /* Skip spaces */
s++;
s = skip_spaces(s);
if (*s == '\0') {
p = s;

View File

@ -4,7 +4,16 @@
#include <linux/string.h>
#include <stdlib.h>
#include "sane_ctype.h"
#include <linux/ctype.h>
const char *graph_dotted_line =
"---------------------------------------------------------------------"
"---------------------------------------------------------------------"
"---------------------------------------------------------------------";
const char *dots =
"....................................................................."
"....................................................................."
".....................................................................";
#define K 1024LL
/*
@ -60,109 +69,6 @@ out_err:
return -1;
}
/*
* Helper function for splitting a string into an argv-like array.
* originally copied from lib/argv_split.c
*/
static const char *skip_sep(const char *cp)
{
while (*cp && isspace(*cp))
cp++;
return cp;
}
static const char *skip_arg(const char *cp)
{
while (*cp && !isspace(*cp))
cp++;
return cp;
}
static int count_argc(const char *str)
{
int count = 0;
while (*str) {
str = skip_sep(str);
if (*str) {
count++;
str = skip_arg(str);
}
}
return count;
}
/**
* argv_free - free an argv
* @argv - the argument vector to be freed
*
* Frees an argv and the strings it points to.
*/
void argv_free(char **argv)
{
char **p;
for (p = argv; *p; p++) {
free(*p);
*p = NULL;
}
free(argv);
}
/**
* argv_split - split a string at whitespace, returning an argv
* @str: the string to be split
* @argcp: returned argument count
*
* Returns an array of pointers to strings which are split out from
* @str. This is performed by strictly splitting on white-space; no
* quote processing is performed. Multiple whitespace characters are
* considered to be a single argument separator. The returned array
* is always NULL-terminated. Returns NULL on memory allocation
* failure.
*/
char **argv_split(const char *str, int *argcp)
{
int argc = count_argc(str);
char **argv = calloc(argc + 1, sizeof(*argv));
char **argvp;
if (argv == NULL)
goto out;
if (argcp)
*argcp = argc;
argvp = argv;
while (*str) {
str = skip_sep(str);
if (*str) {
const char *p = str;
char *t;
str = skip_arg(str);
t = strndup(p, str-p);
if (t == NULL)
goto fail;
*argvp++ = t;
}
}
*argvp = NULL;
out:
return argv;
fail:
argv_free(argv);
return NULL;
}
/* Character class matching */
static bool __match_charclass(const char *pat, char c, const char **npat)
{
@ -303,61 +209,6 @@ int strtailcmp(const char *s1, const char *s2)
return 0;
}
/**
* strxfrchar - Locate and replace character in @s
* @s: The string to be searched/changed.
* @from: Source character to be replaced.
* @to: Destination character.
*
* Return pointer to the changed string.
*/
char *strxfrchar(char *s, char from, char to)
{
char *p = s;
while ((p = strchr(p, from)) != NULL)
*p++ = to;
return s;
}
/**
* ltrim - Removes leading whitespace from @s.
* @s: The string to be stripped.
*
* Return pointer to the first non-whitespace character in @s.
*/
char *ltrim(char *s)
{
while (isspace(*s))
s++;
return s;
}
/**
* rtrim - Removes trailing whitespace from @s.
* @s: The string to be stripped.
*
* Note that the first trailing whitespace is replaced with a %NUL-terminator
* in the given string @s. Returns @s.
*/
char *rtrim(char *s)
{
size_t size = strlen(s);
char *end;
if (!size)
return s;
end = s + size - 1;
while (end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
return s;
}
char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
{
/*

View File

@ -2,13 +2,15 @@
#ifndef PERF_STRING_H
#define PERF_STRING_H
#include <linux/string.h>
#include <linux/types.h>
#include <stddef.h>
#include <string.h>
extern const char *graph_dotted_line;
extern const char *dots;
s64 perf_atoll(const char *str);
char **argv_split(const char *str, int *argcp);
void argv_free(char **argv);
bool strglobmatch(const char *str, const char *pat);
bool strglobmatch_nocase(const char *str, const char *pat);
bool strlazymatch(const char *str, const char *pat);
@ -17,15 +19,6 @@ static inline bool strisglob(const char *str)
return strpbrk(str, "*?[") != NULL;
}
int strtailcmp(const char *s1, const char *s2);
char *strxfrchar(char *s, char from, char to);
char *ltrim(char *s);
char *rtrim(char *s);
static inline char *trim(char *s)
{
return ltrim(rtrim(s));
}
char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints);

View File

@ -14,7 +14,8 @@
#include "machine.h"
#include "vdso.h"
#include "debug.h"
#include "sane_ctype.h"
#include "util.h"
#include <linux/ctype.h>
#include <symbol/kallsyms.h>
#ifndef EM_AARCH64

View File

@ -25,7 +25,7 @@
#include "namespaces.h"
#include "header.h"
#include "path.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
#include <elf.h>
#include <limits.h>

View File

@ -628,6 +628,23 @@ static int thread_stack__bottom(struct thread_stack *ts,
true, false);
}
static int thread_stack__pop_ks(struct thread *thread, struct thread_stack *ts,
struct perf_sample *sample, u64 ref)
{
u64 tm = sample->time;
int err;
/* Return to userspace, so pop all kernel addresses */
while (thread_stack__in_kernel(ts)) {
err = thread_stack__call_return(thread, ts, --ts->cnt,
tm, ref, true);
if (err)
return err;
}
return 0;
}
static int thread_stack__no_call_return(struct thread *thread,
struct thread_stack *ts,
struct perf_sample *sample,
@ -647,12 +664,9 @@ static int thread_stack__no_call_return(struct thread *thread,
if (ip >= ks && addr < ks) {
/* Return to userspace, so pop all kernel addresses */
while (thread_stack__in_kernel(ts)) {
err = thread_stack__call_return(thread, ts, --ts->cnt,
tm, ref, true);
if (err)
return err;
}
err = thread_stack__pop_ks(thread, ts, sample, ref);
if (err)
return err;
/* If the stack is empty, push the userspace address */
if (!ts->cnt) {
@ -662,12 +676,9 @@ static int thread_stack__no_call_return(struct thread *thread,
}
} else if (thread_stack__in_kernel(ts) && ip < ks) {
/* Return to userspace, so pop all kernel addresses */
while (thread_stack__in_kernel(ts)) {
err = thread_stack__call_return(thread, ts, --ts->cnt,
tm, ref, true);
if (err)
return err;
}
err = thread_stack__pop_ks(thread, ts, sample, ref);
if (err)
return err;
}
if (ts->cnt)
@ -910,7 +921,18 @@ int thread_stack__process(struct thread *thread, struct comm *comm,
ts->rstate = X86_RETPOLINE_DETECTED;
} else if (sample->flags & PERF_IP_FLAG_RETURN) {
if (!sample->ip || !sample->addr)
if (!sample->addr) {
u32 return_from_kernel = PERF_IP_FLAG_SYSCALLRET |
PERF_IP_FLAG_INTERRUPT;
if (!(sample->flags & return_from_kernel))
return 0;
/* Pop kernel stack */
return thread_stack__pop_ks(thread, ts, sample, ref);
}
if (!sample->ip)
return 0;
/* x86 retpoline 'return' doesn't match the stack */

View File

@ -12,6 +12,7 @@
#include "strlist.h"
#include <string.h>
#include <api/fs/fs.h>
#include <linux/string.h>
#include "asm/bug.h"
#include "thread_map.h"
#include "util.h"
@ -392,7 +393,7 @@ static int get_comm(char **comm, pid_t pid)
* mark the end of the string.
*/
(*comm)[size] = 0;
rtrim(*comm);
strim(*comm);
}
free(path);

View File

@ -1,13 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdlib.h>
#include <string.h>
#include <linux/string.h>
#include <sys/time.h>
#include <linux/time64.h>
#include <time.h>
#include <errno.h>
#include <inttypes.h>
#include <math.h>
#include <ctype.h>
#include <linux/ctype.h>
#include "perf.h"
#include "debug.h"
@ -141,10 +142,7 @@ static int perf_time__parse_strs(struct perf_time_interval *ptime,
for (i = 0, p = str; i < num - 1; i++) {
arg = p;
/* Find next comma, there must be one */
p = strchr(p, ',') + 1;
/* Skip white space */
while (isspace(*p))
p++;
p = skip_spaces(strchr(p, ',') + 1);
/* Skip the value, must not contain space or comma */
while (*p && !isspace(*p)) {
if (*p++ == ',') {

View File

@ -11,7 +11,7 @@
#include "debug.h"
#include "trace-event.h"
#include "sane_ctype.h"
#include <linux/ctype.h>
static int get_common_field(struct scripting_context *context,
int *offset, int *size, const char *type)

View File

@ -434,19 +434,6 @@ size_t hex_width(u64 v)
return n;
}
/*
* While we find nice hex chars, build a long_val.
* Return number of chars processed.
*/
int hex2u64(const char *ptr, u64 *long_val)
{
char *p;
*long_val = strtoull(ptr, &p, 16);
return p - ptr;
}
int perf_event_paranoid(void)
{
int value;

View File

@ -43,7 +43,6 @@ ssize_t readn(int fd, void *buf, size_t n);
ssize_t writen(int fd, const void *buf, size_t n);
size_t hex_width(u64 v);
int hex2u64(const char *ptr, u64 *val);
extern unsigned int page_size;
int __pure cacheline_size(void);