Commit d207ea8e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates from Thomas Gleixner:
 "Kernel:
   - Improve kallsyms coverage
   - Add x86 entry trampolines to kcore
   - Fix ARM SPE handling
   - Correct PPC event post processing

  Tools:
   - Make the build system more robust
   - Small fixes and enhancements all over the place
   - Update kernel ABI header copies
   - Preparatory work for converting libtraceevnt to a shared library
   - License cleanups"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (100 commits)
  tools arch: Update arch/x86/lib/memcpy_64.S copy used in 'perf bench mem memcpy'
  tools arch x86: Update tools's copy of cpufeatures.h
  perf python: Fix pyrf_evlist__read_on_cpu() interface
  perf mmap: Store real cpu number in 'struct perf_mmap'
  perf tools: Remove ext from struct kmod_path
  perf tools: Add gzip_is_compressed function
  perf tools: Add lzma_is_compressed function
  perf tools: Add is_compressed callback to compressions array
  perf tools: Move the temp file processing into decompress_kmodule
  perf tools: Use compression id in decompress_kmodule()
  perf tools: Store compression id into struct dso
  perf tools: Add compression id into 'struct kmod_path'
  perf tools: Make is_supported_compression() static
  perf tools: Make decompress_to_file() function static
  perf tools: Get rid of dso__needs_decompress() call in __open_dso()
  perf tools: Get rid of dso__needs_decompress() call in symbol__disassemble()
  perf tools: Get rid of dso__needs_decompress() call in read_object_code()
  tools lib traceevent: Change to SPDX License format
  perf llvm: Allow passing options to llc in addition to clang
  perf parser: Improve error message for PMU address filters
  ...
parents 2a8a2b7c 66e5db4a
......@@ -2,6 +2,8 @@
#include <linux/spinlock.h>
#include <linux/percpu.h>
#include <linux/kallsyms.h>
#include <linux/kcore.h>
#include <asm/cpu_entry_area.h>
#include <asm/pgtable.h>
......@@ -13,6 +15,7 @@ static DEFINE_PER_CPU_PAGE_ALIGNED(struct entry_stack_page, entry_stack_storage)
#ifdef CONFIG_X86_64
static DEFINE_PER_CPU_PAGE_ALIGNED(char, exception_stacks
[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]);
static DEFINE_PER_CPU(struct kcore_list, kcore_entry_trampoline);
#endif
struct cpu_entry_area *get_cpu_entry_area(int cpu)
......@@ -146,10 +149,40 @@ static void __init setup_cpu_entry_area(int cpu)
cea_set_pte(&get_cpu_entry_area(cpu)->entry_trampoline,
__pa_symbol(_entry_trampoline), PAGE_KERNEL_RX);
/*
* The cpu_entry_area alias addresses are not in the kernel binary
* so they do not show up in /proc/kcore normally. This adds entries
* for them manually.
*/
kclist_add_remap(&per_cpu(kcore_entry_trampoline, cpu),
_entry_trampoline,
&get_cpu_entry_area(cpu)->entry_trampoline, PAGE_SIZE);
#endif
percpu_setup_debug_store(cpu);
}
#ifdef CONFIG_X86_64
int arch_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
char *name)
{
unsigned int cpu, ncpu = 0;
if (symnum >= num_possible_cpus())
return -EINVAL;
for_each_possible_cpu(cpu) {
if (ncpu++ >= symnum)
break;
}
*value = (unsigned long)&get_cpu_entry_area(cpu)->entry_trampoline;
*type = 't';
strlcpy(name, "__entry_SYSCALL_64_trampoline", KSYM_NAME_LEN);
return 0;
}
#endif
static __init void setup_cpu_entry_area_ptes(void)
{
#ifdef CONFIG_X86_32
......
......@@ -359,8 +359,11 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
phdr->p_type = PT_LOAD;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_offset = kc_vaddr_to_offset(m->addr) + data_offset;
if (m->type == KCORE_REMAP)
phdr->p_vaddr = (size_t)m->vaddr;
else
phdr->p_vaddr = (size_t)m->addr;
if (m->type == KCORE_RAM)
if (m->type == KCORE_RAM || m->type == KCORE_REMAP)
phdr->p_paddr = __pa(m->addr);
else if (m->type == KCORE_TEXT)
phdr->p_paddr = __pa_symbol(m->addr);
......
......@@ -12,11 +12,13 @@ enum kcore_type {
KCORE_VMEMMAP,
KCORE_USER,
KCORE_OTHER,
KCORE_REMAP,
};
struct kcore_list {
struct list_head list;
unsigned long addr;
unsigned long vaddr;
size_t size;
int type;
};
......@@ -36,11 +38,22 @@ struct vmcoredd_node {
#ifdef CONFIG_PROC_KCORE
void __init kclist_add(struct kcore_list *, void *, size_t, int type);
static inline
void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
{
m->vaddr = (unsigned long)vaddr;
kclist_add(m, addr, sz, KCORE_REMAP);
}
#else
static inline
void kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
{
}
static inline
void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
{
}
#endif
#endif /* _LINUX_KCORE_H */
......@@ -432,6 +432,7 @@ int sprint_backtrace(char *buffer, unsigned long address)
/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
struct kallsym_iter {
loff_t pos;
loff_t pos_arch_end;
loff_t pos_mod_end;
loff_t pos_ftrace_mod_end;
unsigned long value;
......@@ -443,9 +444,29 @@ struct kallsym_iter {
int show_value;
};
int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value,
char *type, char *name)
{
return -EINVAL;
}
static int get_ksymbol_arch(struct kallsym_iter *iter)
{
int ret = arch_get_kallsym(iter->pos - kallsyms_num_syms,
&iter->value, &iter->type,
iter->name);
if (ret < 0) {
iter->pos_arch_end = iter->pos;
return 0;
}
return 1;
}
static int get_ksymbol_mod(struct kallsym_iter *iter)
{
int ret = module_get_kallsym(iter->pos - kallsyms_num_syms,
int ret = module_get_kallsym(iter->pos - iter->pos_arch_end,
&iter->value, &iter->type,
iter->name, iter->module_name,
&iter->exported);
......@@ -501,32 +522,34 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos)
iter->nameoff = get_symbol_offset(new_pos);
iter->pos = new_pos;
if (new_pos == 0) {
iter->pos_arch_end = 0;
iter->pos_mod_end = 0;
iter->pos_ftrace_mod_end = 0;
}
}
/*
* The end position (last + 1) of each additional kallsyms section is recorded
* in iter->pos_..._end as each section is added, and so can be used to
* determine which get_ksymbol_...() function to call next.
*/
static int update_iter_mod(struct kallsym_iter *iter, loff_t pos)
{
iter->pos = pos;
if (iter->pos_ftrace_mod_end > 0 &&
iter->pos_ftrace_mod_end < iter->pos)
return get_ksymbol_bpf(iter);
if (iter->pos_mod_end > 0 &&
iter->pos_mod_end < iter->pos) {
if (!get_ksymbol_ftrace_mod(iter))
return get_ksymbol_bpf(iter);
if ((!iter->pos_arch_end || iter->pos_arch_end > pos) &&
get_ksymbol_arch(iter))
return 1;
}
if (!get_ksymbol_mod(iter)) {
if (!get_ksymbol_ftrace_mod(iter))
return get_ksymbol_bpf(iter);
}
if ((!iter->pos_mod_end || iter->pos_mod_end > pos) &&
get_ksymbol_mod(iter))
return 1;
if ((!iter->pos_ftrace_mod_end || iter->pos_ftrace_mod_end > pos) &&
get_ksymbol_ftrace_mod(iter))
return 1;
return get_ksymbol_bpf(iter);
}
/* Returns false if pos at or past end of file. */
......
......@@ -220,6 +220,7 @@
#define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */
#define X86_FEATURE_ZEN ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */
#define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */
#define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */
/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */
......@@ -230,7 +231,7 @@
#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer VMMCALL to VMCALL */
#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */
#define X86_FEATURE_EPT_AD ( 8*32+17) /* Intel Extended Page Table access-dirty bit */
/* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
#define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
......
......@@ -256,7 +256,7 @@ ENTRY(__memcpy_mcsafe)
/* Copy successful. Return zero */
.L_done_memcpy_trap:
xorq %rax, %rax
xorl %eax, %eax
ret
ENDPROC(__memcpy_mcsafe)
EXPORT_SYMBOL_GPL(__memcpy_mcsafe)
......
......@@ -129,12 +129,12 @@ $(OUTPUT)liblockdep.a: $(LIB_IN)
tags: force
$(RM) tags
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
--regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/'
TAGS: force
$(RM) TAGS
find . -name '*.[ch]' | xargs etags \
--regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
--regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/'
define do_install
$(print_install) \
......
......@@ -233,12 +233,12 @@ endef
tags: force
$(RM) tags
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
--regex-c++='/_PE\(([^,)]*).*/TEP_ERRNO__\1/'
TAGS: force
$(RM) TAGS
find . -name '*.[ch]' | xargs etags \
--regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
--regex='/_PE(\([^,)]*\).*/TEP_ERRNO__\1/'
define do_install_mkdir
if [ ! -d '$(DESTDIR_SQ)$1' ]; then \
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <ctype.h>
......@@ -34,7 +20,7 @@
static struct registered_plugin_options {
struct registered_plugin_options *next;
struct pevent_plugin_option *options;
struct tep_plugin_option *options;
} *registered_options;
static struct trace_plugin_options {
......@@ -58,7 +44,7 @@ static void lower_case(char *str)
*str = tolower(*str);
}
static int update_option_value(struct pevent_plugin_option *op, const char *val)
static int update_option_value(struct tep_plugin_option *op, const char *val)
{
char *op_val;
......@@ -97,7 +83,7 @@ static int update_option_value(struct pevent_plugin_option *op, const char *val)
}
/**
* traceevent_plugin_list_options - get list of plugin options
* tep_plugin_list_options - get list of plugin options
*
* Returns an array of char strings that list the currently registered
* plugin options in the format of <plugin>:<option>. This list can be
......@@ -106,12 +92,12 @@ static int update_option_value(struct pevent_plugin_option *op, const char *val)
* Returns NULL if there's no options registered. On error it returns
* INVALID_PLUGIN_LIST_OPTION
*
* Must be freed with traceevent_plugin_free_options_list().
* Must be freed with tep_plugin_free_options_list().
*/
char **traceevent_plugin_list_options(void)
char **tep_plugin_list_options(void)
{
struct registered_plugin_options *reg;
struct pevent_plugin_option *op;
struct tep_plugin_option *op;
char **list = NULL;
char *name;
int count = 0;
......@@ -146,7 +132,7 @@ char **traceevent_plugin_list_options(void)
return INVALID_PLUGIN_LIST_OPTION;
}
void traceevent_plugin_free_options_list(char **list)
void tep_plugin_free_options_list(char **list)
{
int i;
......@@ -163,7 +149,7 @@ void traceevent_plugin_free_options_list(char **list)
}
static int
update_option(const char *file, struct pevent_plugin_option *option)
update_option(const char *file, struct tep_plugin_option *option)
{
struct trace_plugin_options *op;
char *plugin;
......@@ -215,14 +201,14 @@ update_option(const char *file, struct pevent_plugin_option *option)
}
/**
* traceevent_plugin_add_options - Add a set of options by a plugin
* tep_plugin_add_options - Add a set of options by a plugin
* @name: The name of the plugin adding the options
* @options: The set of options being loaded
*
* Sets the options with the values that have been added by user.
*/
int traceevent_plugin_add_options(const char *name,
struct pevent_plugin_option *options)
int tep_plugin_add_options(const char *name,
struct tep_plugin_option *options)
{
struct registered_plugin_options *reg;
......@@ -241,10 +227,10 @@ int traceevent_plugin_add_options(const char *name,
}
/**
* traceevent_plugin_remove_options - remove plugin options that were registered
* @options: Options to removed that were registered with traceevent_plugin_add_options
* tep_plugin_remove_options - remove plugin options that were registered
* @options: Options to removed that were registered with tep_plugin_add_options
*/
void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
void tep_plugin_remove_options(struct tep_plugin_option *options)
{
struct registered_plugin_options **last;
struct registered_plugin_options *reg;
......@@ -260,17 +246,17 @@ void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
}
/**
* traceevent_print_plugins - print out the list of plugins loaded
* tep_print_plugins - print out the list of plugins loaded
* @s: the trace_seq descripter to write to
* @prefix: The prefix string to add before listing the option name
* @suffix: The suffix string ot append after the option name
* @list: The list of plugins (usually returned by traceevent_load_plugins()
* @list: The list of plugins (usually returned by tep_load_plugins()
*
* Writes to the trace_seq @s the list of plugins (files) that is
* returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
* returned by tep_load_plugins(). Use @prefix and @suffix for formating:
* @prefix = " ", @suffix = "\n".
*/
void traceevent_print_plugins(struct trace_seq *s,
void tep_print_plugins(struct trace_seq *s,
const char *prefix, const char *suffix,
const struct plugin_list *list)
{
......@@ -281,11 +267,11 @@ void traceevent_print_plugins(struct trace_seq *s,
}
static void
load_plugin(struct pevent *pevent, const char *path,
load_plugin(struct tep_handle *pevent, const char *path,
const char *file, void *data)
{
struct plugin_list **plugin_list = data;
pevent_plugin_load_func func;
tep_plugin_load_func func;
struct plugin_list *list;
const char *alias;
char *plugin;
......@@ -305,14 +291,14 @@ load_plugin(struct pevent *pevent, const char *path,
goto out_free;
}
alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME);
alias = dlsym(handle, TEP_PLUGIN_ALIAS_NAME);
if (!alias)
alias = file;
func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME);
func = dlsym(handle, TEP_PLUGIN_LOADER_NAME);
if (!func) {
warning("could not find func '%s' in plugin '%s'\n%s\n",
PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror());
TEP_PLUGIN_LOADER_NAME, plugin, dlerror());
goto out_free;
}
......@@ -336,9 +322,9 @@ load_plugin(struct pevent *pevent, const char *path,
}
static void
load_plugins_dir(struct pevent *pevent, const char *suffix,
load_plugins_dir(struct tep_handle *pevent, const char *suffix,
const char *path,
void (*load_plugin)(struct pevent *pevent,
void (*load_plugin)(struct tep_handle *pevent,
const char *path,
const char *name,
void *data),
......@@ -378,8 +364,8 @@ load_plugins_dir(struct pevent *pevent, const char *suffix,
}
static void
load_plugins(struct pevent *pevent, const char *suffix,
void (*load_plugin)(struct pevent *pevent,
load_plugins(struct tep_handle *pevent, const char *suffix,
void (*load_plugin)(struct tep_handle *pevent,
const char *path,
const char *name,
void *data),
......@@ -390,7 +376,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
char *envdir;
int ret;
if (pevent->flags & PEVENT_DISABLE_PLUGINS)
if (pevent->flags & TEP_DISABLE_PLUGINS)
return;
/*
......@@ -398,7 +384,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
* check that first.
*/
#ifdef PLUGIN_DIR
if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
if (!(pevent->flags & TEP_DISABLE_SYS_PLUGINS))
load_plugins_dir(pevent, suffix, PLUGIN_DIR,
load_plugin, data);
#endif
......@@ -431,7 +417,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
}
struct plugin_list*
traceevent_load_plugins(struct pevent *pevent)
tep_load_plugins(struct tep_handle *pevent)
{
struct plugin_list *list = NULL;
......@@ -440,15 +426,15 @@ traceevent_load_plugins(struct pevent *pevent)
}
void
traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent)
tep_unload_plugins(struct plugin_list *plugin_list, struct tep_handle *pevent)
{
pevent_plugin_unload_func func;
tep_plugin_unload_func func;
struct plugin_list *list;
while (plugin_list) {
list = plugin_list;
plugin_list = list->next;
func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME);
func = dlsym(list->handle, TEP_PLUGIN_UNLOADER_NAME);
if (func)
func(pevent);
dlclose(list->handle);
......
/* SPDX-License-Identifier: LGPL-2.1 */
/*
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#ifndef __UTIL_H
#define __UTIL_H
......
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
......
This diff is collapsed.
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
......
......@@ -25,19 +25,19 @@ process___le16_to_cpup(struct trace_seq *s, unsigned long long *args)
return val ? (long long) le16toh(*val) : 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_print_function(pevent,
tep_register_print_function(pevent,
process___le16_to_cpup,
PEVENT_FUNC_ARG_INT,
TEP_FUNC_ARG_INT,
"__le16_to_cpup",
PEVENT_FUNC_ARG_PTR,
PEVENT_FUNC_ARG_VOID);
TEP_FUNC_ARG_PTR,
TEP_FUNC_ARG_VOID);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_print_function(pevent, process___le16_to_cpup,
tep_unregister_print_function(pevent, process___le16_to_cpup,
"__le16_to_cpup");
}
......@@ -33,7 +33,7 @@ static int cpus = -1;
#define STK_BLK 10
struct pevent_plugin_option plugin_options[] =
struct tep_plugin_option plugin_options[] =
{
{
.name = "parent",
......@@ -53,8 +53,8 @@ struct pevent_plugin_option plugin_options[] =
}
};
static struct pevent_plugin_option *ftrace_parent = &plugin_options[0];
static struct pevent_plugin_option *ftrace_indent = &plugin_options[1];
static struct tep_plugin_option *ftrace_parent = &plugin_options[0];
static struct tep_plugin_option *ftrace_indent = &plugin_options[1];
static void add_child(struct func_stack *stack, const char *child, int pos)
{
......@@ -122,25 +122,25 @@ static int add_and_get_index(const char *parent, const char *child, int cpu)
return 0;
}
static int function_handler(struct trace_seq *s, struct pevent_record *record,
static int function_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
{
struct pevent *pevent = event->pevent;
struct tep_handle *pevent = event->pevent;
unsigned long long function;
unsigned long long pfunction;
const char *func;
const char *parent;
int index = 0;
if (pevent_get_field_val(s, event, "ip", record, &function, 1))
if (tep_get_field_val(s, event, "ip", record, &function, 1))
return trace_seq_putc(s, '!');
func = pevent_find_function(pevent, function);
func = tep_find_function(pevent, function);
if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
if (tep_get_field_val(s, event, "parent_ip", record, &pfunction, 1))
return trace_seq_putc(s, '!');
parent = pevent_find_function(pevent, pfunction);
parent = tep_find_function(pevent, pfunction);
if (parent && ftrace_indent->set)
index = add_and_get_index(parent, func, record->cpu);
......@@ -163,21 +163,21 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_event_handler(pevent, -1, "ftrace", "function",
tep_register_event_handler(pevent, -1, "ftrace", "function",
function_handler, NULL);
traceevent_plugin_add_options("ftrace", plugin_options);
tep_plugin_add_options("ftrace", plugin_options);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
int i, x;
pevent_unregister_event_handler(pevent, -1, "ftrace", "function",
tep_unregister_event_handler(pevent, -1, "ftrace", "function",
function_handler, NULL);
for (i = 0; i <= cpus; i++) {
......@@ -186,7 +186,7 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
free(fstack[i].stack);
}
traceevent_plugin_remove_options(plugin_options);
tep_plugin_remove_options(plugin_options);
free(fstack);
fstack = NULL;
......
......@@ -25,64 +25,64 @@
#include "event-parse.h"
static int timer_expire_handler(struct trace_seq *s,
struct pevent_record *record,
struct tep_record *record,
struct event_format *event, void *context)
{
trace_seq_printf(s, "hrtimer=");
if (pevent_print_num_field(s, "0x%llx", event, "timer",
if (tep_print_num_field(s, "0x%llx", event, "timer",
record, 0) == -1)
pevent_print_num_field(s, "0x%llx", event, "hrtimer",
tep_print_num_field(s, "0x%llx", event, "hrtimer",
record, 1);
trace_seq_printf(s, " now=");
pevent_print_num_field(s, "%llu", event, "now", record, 1);
tep_print_num_field(s, "%llu", event, "now", record, 1);
pevent_print_func_field(s, " function=%s", event, "function",
tep_print_func_field(s, " function=%s", event, "function",
record, 0);
return 0;
}
static int timer_start_handler(struct trace_seq *s,
struct pevent_record *record,
struct tep_record *record,
struct event_format *event, void *context)
{
trace_seq_printf(s, "hrtimer=");
if (pevent_print_num_field(s, "0x%llx", event, "timer",
if (tep_print_num_field(s, "0x%llx", event, "timer",
record, 0) == -1)
pevent_print_num_field(s, "0x%llx", event, "hrtimer",
tep_print_num_field(s, "0x%llx", event, "hrtimer",
record, 1);
pevent_print_func_field(s, " function=%s", event, "function",
tep_print_func_field(s, " function=%s", event, "function",
record, 0);
trace_seq_printf(s, " expires=");
pevent_print_num_field(s, "%llu", event, "expires", record, 1);
tep_print_num_field(s, "%llu", event, "expires", record, 1);
trace_seq_printf(s, " softexpires=");
pevent_print_num_field(s, "%llu", event, "softexpires", record, 1);
tep_print_num_field(s, "%llu", event, "softexpires", record, 1);
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_event_handler(pevent, -1,
tep_register_event_handler(pevent, -1,
"timer", "hrtimer_expire_entry",
timer_expire_handler, NULL);
pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start",
tep_register_event_handler(pevent, -1, "timer", "hrtimer_start",
timer_start_handler, NULL);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_event_handler(pevent, -1,
tep_unregister_event_handler(pevent, -1,
"timer", "hrtimer_expire_entry",
timer_expire_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
tep_unregister_event_handler(pevent, -1, "timer", "hrtimer_start",
timer_start_handler, NULL);
}
......@@ -47,29 +47,29 @@ process_jiffies_to_msecs(struct trace_seq *s, unsigned long long *args)
return jiffies;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_print_function(pevent,
tep_register_print_function(pevent,
process_jbd2_dev_to_name,
PEVENT_FUNC_ARG_STRING,
TEP_FUNC_ARG_STRING,
"jbd2_dev_to_name",
PEVENT_FUNC_ARG_INT,
PEVENT_FUNC_ARG_VOID);
TEP_FUNC_ARG_INT,
TEP_FUNC_ARG_VOID);
pevent_register_print_function(pevent,
tep_register_print_function(pevent,
process_jiffies_to_msecs,
PEVENT_FUNC_ARG_LONG,
TEP_FUNC_ARG_LONG,
"jiffies_to_msecs",
PEVENT_FUNC_ARG_LONG,
PEVENT_FUNC_ARG_VOID);
TEP_FUNC_ARG_LONG,
TEP_FUNC_ARG_VOID);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_print_function(pevent, process_jbd2_dev_to_name,
tep_unregister_print_function(pevent, process_jbd2_dev_to_name,
"jbd2_dev_to_name");
pevent_unregister_print_function(pevent, process_jiffies_to_msecs,
tep_unregister_print_function(pevent, process_jiffies_to_msecs,
"jiffies_to_msecs");
}
......@@ -23,7 +23,7 @@
#include "event-parse.h"
static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
static int call_site_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
{
struct format_field *field;
......@@ -31,64 +31,64 @@ static int call_site_handler(struct trace_seq *s, struct pevent_record *record,
void *data = record->data;
const char *func;
field = pevent_find_field(event, "call_site");
field = tep_find_field(event, "call_site");
if (!field)
return 1;
if (pevent_read_number_field(field, data, &val))
if (tep_read_number_field(field, data, &val))
return 1;
func = pevent_find_function(event->pevent, val);
func = tep_find_function(event->pevent, val);
if (!func)
return 1;
addr = pevent_find_function_address(event->pevent, val);
addr = tep_find_function_address(event->pevent, val);
trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr));
return 1;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_event_handler(pevent, -1, "kmem", "kfree",
tep_register_event_handler(pevent, -1, "kmem", "kfree",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmalloc",
tep_register_event_handler(pevent, -1, "kmem", "kmalloc",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
tep_register_event_handler(pevent, -1, "kmem", "kmalloc_node",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem",
tep_register_event_handler(pevent, -1, "kmem",
"kmem_cache_alloc_node",
call_site_handler, NULL);
pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
tep_register_event_handler(pevent, -1, "kmem", "kmem_cache_free",
call_site_handler, NULL);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_event_handler(pevent, -1, "kmem", "kfree",
tep_unregister_event_handler(pevent, -1, "kmem", "kfree",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
tep_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem",
tep_unregister_event_handler(pevent, -1, "kmem",
"kmem_cache_alloc_node",
call_site_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
tep_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free",
call_site_handler, NULL);
}
This diff is collapsed.
......@@ -28,7 +28,7 @@
static void print_string(struct trace_seq *s, struct event_format *event,
const char *name, const void *data)
{
struct format_field *f = pevent_find_field(event, name);
struct format_field *f = tep_find_field(event, name);
int offset;
int length;
......@@ -42,7 +42,7 @@ static void print_string(struct trace_seq *s, struct event_format *event,
if (!strncmp(f->type, "__data_loc", 10)) {
unsigned long long v;
if (pevent_read_number_field(f, data, &v)) {
if (tep_read_number_field(f, data, &v)) {
trace_seq_printf(s, "invalid_data_loc");
return;
}
......@@ -53,12 +53,12 @@ static void print_string(struct trace_seq *s, struct event_format *event,
trace_seq_printf(s, "%.*s", length, (char *)data + offset);
}
#define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0)
#define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0)
#define SF(fn) tep_print_num_field(s, fn ":%d", event, fn, record, 0)
#define SFX(fn) tep_print_num_field(s, fn ":%#x", event, fn, record, 0)
#define SP() trace_seq_putc(s, ' ')
static int drv_bss_info_changed(struct trace_seq *s,
struct pevent_record *record,
struct tep_record *record,
struct event_format *event, void *context)
{
void *data = record->data;
......@@ -66,7 +66,7 @@ static int drv_bss_info_changed(struct trace_seq *s,
print_string(s, event, "wiphy_name", data);
trace_seq_printf(s, " vif:");
print_string(s, event, "vif_name", data);
pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1);
tep_print_num_field(s, "(%d)", event, "vif_type", record, 1);
trace_seq_printf(s, "\n%*s", INDENT, "");
SF("assoc"); SP();
......@@ -86,17 +86,17 @@ static int drv_bss_info_changed(struct trace_seq *s,
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_event_handler(pevent, -1, "mac80211",
tep_register_event_handler(pevent, -1, "mac80211",
"drv_bss_info_changed",
drv_bss_info_changed, NULL);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_event_handler(pevent, -1, "mac80211",
tep_unregister_event_handler(pevent, -1, "mac80211",
"drv_bss_info_changed",
drv_bss_info_changed, NULL);
}
......@@ -45,7 +45,7 @@ static void write_state(struct trace_seq *s, int val)
}
static void write_and_save_comm(struct format_field *field,
struct pevent_record *record,
struct tep_record *record,
struct trace_seq *s, int pid)
{
const char *comm;
......@@ -61,100 +61,100 @@ static void write_and_save_comm(struct format_field *field,
comm = &s->buffer[len];
/* Help out the comm to ids. This will handle dups */
pevent_register_comm(field->event->pevent, comm, pid);
tep_register_comm(field->event->pevent, comm, pid);
}
static int sched_wakeup_handler(struct trace_seq *s,
struct pevent_record *record,
struct tep_record *record,
struct event_format *event, void *context)
{
struct format_field *field;
unsigned long long val;
if (pevent_get_field_val(s, event, "pid", record, &val, 1))
if (tep_get_field_val(s, event, "pid", record, &val, 1))
return trace_seq_putc(s, '!');
field = pevent_find_any_field(event, "comm");
field = tep_find_any_field(event, "comm");
if (field) {
write_and_save_comm(field, record, s, val);
trace_seq_putc(s, ':');
}
trace_seq_printf(s, "%lld", val);
if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0)
if (tep_get_field_val(s, event, "prio", record, &val, 0) == 0)
trace_seq_printf(s, " [%lld]", val);
if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0)
if (tep_get_field_val(s, event, "success", record, &val, 1) == 0)
trace_seq_printf(s, " success=%lld", val);
if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
if (tep_get_field_val(s, event, "target_cpu", record, &val, 0) == 0)
trace_seq_printf(s, " CPU:%03llu", val);
return 0;
}
static int sched_switch_handler(struct trace_seq *s,
struct pevent_record *record,
struct tep_record *record,
struct event_format *event, void *context)
{
struct format_field *field;
unsigned long long val;
if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1))
if (tep_get_field_val(s, event, "prev_pid", record, &val, 1))
return trace_seq_putc(s, '!');
field = pevent_find_any_field(event, "prev_comm");
field = tep_find_any_field(event, "prev_comm");
if (field) {
write_and_save_comm(field, record, s, val);
trace_seq_putc(s, ':');
}
trace_seq_printf(s, "%lld ", val);
if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
if (tep_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
trace_seq_printf(s, "[%d] ", (int) val);
if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
if (tep_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
write_state(s, val);
trace_seq_puts(s, " ==> ");
if (pevent_get_field_val(s, event, "next_pid", record, &val, 1))
if (tep_get_field_val(s, event, "next_pid", record, &val, 1))
return trace_seq_putc(s, '!');
field = pevent_find_any_field(event, "next_comm");
field = tep_find_any_field(event, "next_comm");
if (field) {
write_and_save_comm(field, record, s, val);
trace_seq_putc(s, ':');
}
trace_seq_printf(s, "%lld", val);
if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
if (tep_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
trace_seq_printf(s, " [%d]", (int) val);
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_event_handler(pevent, -1, "sched", "sched_switch",
tep_register_event_handler(pevent, -1, "sched", "sched_switch",
sched_switch_handler, NULL);
pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup",
tep_register_event_handler(pevent, -1, "sched", "sched_wakeup",
sched_wakeup_handler, NULL);
pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
tep_register_event_handler(pevent, -1, "sched", "sched_wakeup_new",
sched_wakeup_handler, NULL);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch",
tep_unregister_event_handler(pevent, -1, "sched", "sched_switch",
sched_switch_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup",
sched_wakeup_handler, NULL);
pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
tep_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new",
sched_wakeup_handler, NULL);
}
......@@ -413,21 +413,21 @@ unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s,
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_print_function(pevent,
tep_register_print_function(pevent,
process_scsi_trace_parse_cdb,
PEVENT_FUNC_ARG_STRING,
TEP_FUNC_ARG_STRING,
"scsi_trace_parse_cdb",
PEVENT_FUNC_ARG_PTR,
PEVENT_FUNC_ARG_PTR,
PEVENT_FUNC_ARG_INT,
PEVENT_FUNC_ARG_VOID);
TEP_FUNC_ARG_PTR,
TEP_FUNC_ARG_PTR,
TEP_FUNC_ARG_INT,
TEP_FUNC_ARG_VOID);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
tep_unregister_print_function(pevent, process_scsi_trace_parse_cdb,
"scsi_trace_parse_cdb");
}
......@@ -119,19 +119,19 @@ unsigned long long process_xen_hypercall_name(struct trace_seq *s,
return 0;
}
int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
int TEP_PLUGIN_LOADER(struct tep_handle *pevent)
{
pevent_register_print_function(pevent,
tep_register_print_function(pevent,
process_xen_hypercall_name,
PEVENT_FUNC_ARG_STRING,
TEP_FUNC_ARG_STRING,
"xen_hypercall_name",
PEVENT_FUNC_ARG_INT,
PEVENT_FUNC_ARG_VOID);
TEP_FUNC_ARG_INT,
TEP_FUNC_ARG_VOID);
return 0;
}
void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
void TEP_PLUGIN_UNLOADER(struct tep_handle *pevent)
{
pevent_unregister_print_function(pevent, process_xen_hypercall_name,
tep_unregister_print_function(pevent, process_xen_hypercall_name,
"xen_hypercall_name");
}
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include <stdlib.h>
......
......@@ -118,6 +118,15 @@ OPTIONS
--group::
Show event group information together
--percent-type::
Set annotation percent type from following choices:
global-period, local-period, global-hits, local-hits
The local/global keywords set if the percentage is computed
in the scope of the function (local) or the whole data (global).
The period/hits keywords set the base the percentage is computed
on - the samples period or the number of samples (hits).
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-report[1]
This diff is collapsed.
This diff is collapsed.
......@@ -194,6 +194,7 @@ struct auxtrace_record *arm_spe_recording_init(int *err,
sper->itr.read_finish = arm_spe_read_finish;
sper->itr.alignment = 0;
*err = 0;
return &sper->itr;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment