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

Pull perf updates from Ingo Molnar:
 "The main updates in this cycle were:

   - Lots of perf tooling changes too voluminous to list (big perf trace
     and perf stat improvements, lots of libtraceevent reorganization,
     etc.), so I'll list the authors and refer to the changelog for
     details:

       Benjamin Peterson, Jérémie Galarneau, Kim Phillips, Peter
       Zijlstra, Ravi Bangoria, Sangwon Hong, Sean V Kelley, Steven
       Rostedt, Thomas Gleixner, Ding Xiang, Eduardo Habkost, Thomas
       Richter, Andi Kleen, Sanskriti Sharma, Adrian Hunter, Tzvetomir
       Stoyanov, Arnaldo Carvalho de Melo, Jiri Olsa.

     ... with the bulk of the changes written by Jiri Olsa, Tzvetomir
     Stoyanov and Arnaldo Carvalho de Melo.

   - Continued intel_rdt work with a focus on playing well with perf
     events. This also imported some non-perf RDT work due to
     dependencies. (Reinette Chatre)

   - Implement counter freezing for Arch Perfmon v4 (Skylake and newer).
     This allows to speed up the PMI handler by avoiding unnecessary MSR
     writes and make it more accurate. (Andi Kleen)

   - kprobes cleanups and simplification (Masami Hiramatsu)

   - Intel Goldmont PMU updates (Kan Liang)

   - ... plus misc other fixes and updates"

* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (155 commits)
  kprobes/x86: Use preempt_enable() in optimized_callback()
  x86/intel_rdt: Prevent pseudo-locking from using stale pointers
  kprobes, x86/ptrace.h: Make regs_get_kernel_stack_nth() not fault on bad stack
  perf/x86/intel: Export mem events only if there's PEBS support
  x86/cpu: Drop pointless static qualifier in punit_dev_state_show()
  x86/intel_rdt: Fix initial allocation to consider CDP
  x86/intel_rdt: CBM overlap should also check for overlap with CDP peer
  x86/intel_rdt: Introduce utility to obtain CDP peer
  tools lib traceevent, perf tools: Move struct tep_handler definition in a local header file
  tools lib traceevent: Separate out tep_strerror() for strerror_r() issues
  perf python: More portable way to make CFLAGS work with clang
  perf python: Make clang_has_option() work on Python 3
  perf tools: Free temporary 'sys' string in read_event_files()
  perf tools: Avoid double free in read_event_file()
  perf tools: Free 'printk' string in parse_ftrace_printk()
  perf tools: Cleanup trace-event-info 'tdata' leak
  perf strbuf: Match va_{add,copy} with va_end
  perf test: S390 does not support watchpoints in test 22
  perf auxtrace: Include missing asm/bitsperlong.h to get BITS_PER_LONG
  tools include: Adopt linux/bits.h
  ...
This commit is contained in:
Linus Torvalds 2018-10-23 13:32:18 +01:00
commit c05f3642f4
141 changed files with 6261 additions and 3870 deletions

View file

@ -23,6 +23,13 @@ void pager_init(const char *pager_env)
subcmd_config.pager_env = pager_env;
}
static const char *forced_pager;
void force_pager(const char *pager)
{
forced_pager = pager;
}
static void pager_preexec(void)
{
/*
@ -66,7 +73,9 @@ void setup_pager(void)
const char *pager = getenv(subcmd_config.pager_env);
struct winsize sz;
if (!isatty(1))
if (forced_pager)
pager = forced_pager;
if (!isatty(1) && !forced_pager)
return;
if (ioctl(1, TIOCGWINSZ, &sz) == 0)
pager_columns = sz.ws_col;

View file

@ -7,5 +7,6 @@ extern void pager_init(const char *pager_env);
extern void setup_pager(void);
extern int pager_in_use(void);
extern int pager_get_columns(void);
extern void force_pager(const char *);
#endif /* __SUBCMD_PAGER_H */

View file

@ -4,6 +4,8 @@ libtraceevent-y += trace-seq.o
libtraceevent-y += parse-filter.o
libtraceevent-y += parse-utils.o
libtraceevent-y += kbuffer-parse.o
libtraceevent-y += tep_strerror.o
libtraceevent-y += event-parse-api.o
plugin_jbd2-y += plugin_jbd2.o
plugin_hrtimer-y += plugin_hrtimer.o

View file

@ -0,0 +1,275 @@
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
*/
#include "event-parse.h"
#include "event-parse-local.h"
#include "event-utils.h"
/**
* tep_get_first_event - returns the first event in the events array
* @tep: a handle to the tep_handle
*
* This returns pointer to the first element of the events array
* If @tep is NULL, NULL is returned.
*/
struct tep_event_format *tep_get_first_event(struct tep_handle *tep)
{
if (tep && tep->events)
return tep->events[0];
return NULL;
}
/**
* tep_get_events_count - get the number of defined events
* @tep: a handle to the tep_handle
*
* This returns number of elements in event array
* If @tep is NULL, 0 is returned.
*/
int tep_get_events_count(struct tep_handle *tep)
{
if(tep)
return tep->nr_events;
return 0;
}
/**
* tep_set_flag - set event parser flag
* @tep: a handle to the tep_handle
* @flag: flag, or combination of flags to be set
* can be any combination from enum tep_flag
*
* This sets a flag or mbination of flags from enum tep_flag
*/
void tep_set_flag(struct tep_handle *tep, int flag)
{
if(tep)
tep->flags |= flag;
}
unsigned short __tep_data2host2(struct tep_handle *pevent, unsigned short data)
{
unsigned short swap;
if (!pevent || pevent->host_bigendian == pevent->file_bigendian)
return data;
swap = ((data & 0xffULL) << 8) |
((data & (0xffULL << 8)) >> 8);
return swap;
}
unsigned int __tep_data2host4(struct tep_handle *pevent, unsigned int data)
{
unsigned int swap;
if (!pevent || pevent->host_bigendian == pevent->file_bigendian)
return data;
swap = ((data & 0xffULL) << 24) |
((data & (0xffULL << 8)) << 8) |
((data & (0xffULL << 16)) >> 8) |
((data & (0xffULL << 24)) >> 24);
return swap;
}
unsigned long long
__tep_data2host8(struct tep_handle *pevent, unsigned long long data)
{
unsigned long long swap;
if (!pevent || pevent->host_bigendian == pevent->file_bigendian)
return data;
swap = ((data & 0xffULL) << 56) |
((data & (0xffULL << 8)) << 40) |
((data & (0xffULL << 16)) << 24) |
((data & (0xffULL << 24)) << 8) |
((data & (0xffULL << 32)) >> 8) |
((data & (0xffULL << 40)) >> 24) |
((data & (0xffULL << 48)) >> 40) |
((data & (0xffULL << 56)) >> 56);
return swap;
}
/**
* tep_get_header_page_size - get size of the header page
* @pevent: a handle to the tep_handle
*
* This returns size of the header page
* If @pevent is NULL, 0 is returned.
*/
int tep_get_header_page_size(struct tep_handle *pevent)
{
if(pevent)
return pevent->header_page_size_size;
return 0;
}
/**
* tep_get_cpus - get the number of CPUs
* @pevent: a handle to the tep_handle
*
* This returns the number of CPUs
* If @pevent is NULL, 0 is returned.
*/
int tep_get_cpus(struct tep_handle *pevent)
{
if(pevent)
return pevent->cpus;
return 0;
}
/**
* tep_set_cpus - set the number of CPUs
* @pevent: a handle to the tep_handle
*
* This sets the number of CPUs
*/
void tep_set_cpus(struct tep_handle *pevent, int cpus)
{
if(pevent)
pevent->cpus = cpus;
}
/**
* tep_get_long_size - get the size of a long integer on the current machine
* @pevent: a handle to the tep_handle
*
* This returns the size of a long integer on the current machine
* If @pevent is NULL, 0 is returned.
*/
int tep_get_long_size(struct tep_handle *pevent)
{
if(pevent)
return pevent->long_size;
return 0;
}
/**
* tep_set_long_size - set the size of a long integer on the current machine
* @pevent: a handle to the tep_handle
* @size: size, in bytes, of a long integer
*
* This sets the size of a long integer on the current machine
*/
void tep_set_long_size(struct tep_handle *pevent, int long_size)
{
if(pevent)
pevent->long_size = long_size;
}
/**
* tep_get_page_size - get the size of a memory page on the current machine
* @pevent: a handle to the tep_handle
*
* This returns the size of a memory page on the current machine
* If @pevent is NULL, 0 is returned.
*/
int tep_get_page_size(struct tep_handle *pevent)
{
if(pevent)
return pevent->page_size;
return 0;
}
/**
* tep_set_page_size - set the size of a memory page on the current machine
* @pevent: a handle to the tep_handle
* @_page_size: size of a memory page, in bytes
*
* This sets the size of a memory page on the current machine
*/
void tep_set_page_size(struct tep_handle *pevent, int _page_size)
{
if(pevent)
pevent->page_size = _page_size;
}
/**
* tep_is_file_bigendian - get if the file is in big endian order
* @pevent: a handle to the tep_handle
*
* This returns if the file is in big endian order
* If @pevent is NULL, 0 is returned.
*/
int tep_is_file_bigendian(struct tep_handle *pevent)
{
if(pevent)
return pevent->file_bigendian;
return 0;
}
/**
* tep_set_file_bigendian - set if the file is in big endian order
* @pevent: a handle to the tep_handle
* @endian: non zero, if the file is in big endian order
*
* This sets if the file is in big endian order
*/
void tep_set_file_bigendian(struct tep_handle *pevent, enum tep_endian endian)
{
if(pevent)
pevent->file_bigendian = endian;
}
/**
* tep_is_host_bigendian - get if the order of the current host is big endian
* @pevent: a handle to the tep_handle
*
* This gets if the order of the current host is big endian
* If @pevent is NULL, 0 is returned.
*/
int tep_is_host_bigendian(struct tep_handle *pevent)
{
if(pevent)
return pevent->host_bigendian;
return 0;
}
/**
* tep_set_host_bigendian - set the order of the local host
* @pevent: a handle to the tep_handle
* @endian: non zero, if the local host has big endian order
*
* This sets the order of the local host
*/
void tep_set_host_bigendian(struct tep_handle *pevent, enum tep_endian endian)
{
if(pevent)
pevent->host_bigendian = endian;
}
/**
* tep_is_latency_format - get if the latency output format is configured
* @pevent: a handle to the tep_handle
*
* This gets if the latency output format is configured
* If @pevent is NULL, 0 is returned.
*/
int tep_is_latency_format(struct tep_handle *pevent)
{
if(pevent)
return pevent->latency_format;
return 0;
}
/**
* tep_set_latency_format - set the latency output format
* @pevent: a handle to the tep_handle
* @lat: non zero for latency output format
*
* This sets the latency output format
*/
void tep_set_latency_format(struct tep_handle *pevent, int lat)
{
if(pevent)
pevent->latency_format = lat;
}

View file

@ -0,0 +1,92 @@
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
*/
#ifndef _PARSE_EVENTS_INT_H
#define _PARSE_EVENTS_INT_H
struct cmdline;
struct cmdline_list;
struct func_map;
struct func_list;
struct event_handler;
struct func_resolver;
struct tep_handle {
int ref_count;
int header_page_ts_offset;
int header_page_ts_size;
int header_page_size_offset;
int header_page_size_size;
int header_page_data_offset;
int header_page_data_size;
int header_page_overwrite;
enum tep_endian file_bigendian;
enum tep_endian host_bigendian;
int latency_format;
int old_format;
int cpus;
int long_size;
int page_size;
struct cmdline *cmdlines;
struct cmdline_list *cmdlist;
int cmdline_count;
struct func_map *func_map;
struct func_resolver *func_resolver;
struct func_list *funclist;
unsigned int func_count;
struct printk_map *printk_map;
struct printk_list *printklist;
unsigned int printk_count;
struct tep_event_format **events;
int nr_events;
struct tep_event_format **sort_events;
enum tep_event_sort_type last_type;
int type_offset;
int type_size;
int pid_offset;
int pid_size;
int pc_offset;
int pc_size;
int flags_offset;
int flags_size;
int ld_offset;
int ld_size;
int print_raw;
int test_filters;
int flags;
struct tep_format_field *bprint_ip_field;
struct tep_format_field *bprint_fmt_field;
struct tep_format_field *bprint_buf_field;
struct event_handler *handlers;
struct tep_function_handler *func_handlers;
/* cache */
struct tep_event_format *last_event;
char *trace_clock;
};
#endif /* _PARSE_EVENTS_INT_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,9 @@
#include <unistd.h>
#include <dirent.h>
#include "event-parse.h"
#include "event-parse-local.h"
#include "event-utils.h"
#include "trace-seq.h"
#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
@ -30,8 +32,8 @@ static struct trace_plugin_options {
char *value;
} *trace_plugin_options;
struct plugin_list {
struct plugin_list *next;
struct tep_plugin_list {
struct tep_plugin_list *next;
char *name;
void *handle;
};
@ -258,7 +260,7 @@ void tep_plugin_remove_options(struct tep_plugin_option *options)
*/
void tep_print_plugins(struct trace_seq *s,
const char *prefix, const char *suffix,
const struct plugin_list *list)
const struct tep_plugin_list *list)
{
while (list) {
trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
@ -270,9 +272,9 @@ static void
load_plugin(struct tep_handle *pevent, const char *path,
const char *file, void *data)
{
struct plugin_list **plugin_list = data;
struct tep_plugin_list **plugin_list = data;
tep_plugin_load_func func;
struct plugin_list *list;
struct tep_plugin_list *list;
const char *alias;
char *plugin;
void *handle;
@ -416,20 +418,20 @@ load_plugins(struct tep_handle *pevent, const char *suffix,
free(path);
}
struct plugin_list*
struct tep_plugin_list*
tep_load_plugins(struct tep_handle *pevent)
{
struct plugin_list *list = NULL;
struct tep_plugin_list *list = NULL;
load_plugins(pevent, ".so", load_plugin, &list);
return list;
}
void
tep_unload_plugins(struct plugin_list *plugin_list, struct tep_handle *pevent)
tep_unload_plugins(struct tep_plugin_list *plugin_list, struct tep_handle *pevent)
{
tep_plugin_unload_func func;
struct plugin_list *list;
struct tep_plugin_list *list;
while (plugin_list) {
list = plugin_list;

File diff suppressed because it is too large Load diff

View file

@ -23,6 +23,7 @@
#include "event-parse.h"
#include "event-utils.h"
#include "trace-seq.h"
static struct func_stack {
int size;
@ -123,7 +124,7 @@ static int add_and_get_index(const char *parent, const char *child, int cpu)
}
static int function_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
struct tep_handle *pevent = event->pevent;
unsigned long long function;

View file

@ -23,10 +23,11 @@
#include <string.h>
#include "event-parse.h"
#include "trace-seq.h"
static int timer_expire_handler(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
trace_seq_printf(s, "hrtimer=");
@ -46,7 +47,7 @@ static int timer_expire_handler(struct trace_seq *s,
static int timer_start_handler(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
trace_seq_printf(s, "hrtimer=");

View file

@ -22,6 +22,7 @@
#include <string.h>
#include "event-parse.h"
#include "trace-seq.h"
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)

View file

@ -22,11 +22,12 @@
#include <string.h>
#include "event-parse.h"
#include "trace-seq.h"
static int call_site_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
struct format_field *field;
struct tep_format_field *field;
unsigned long long val, addr;
void *data = record->data;
const char *func;

View file

@ -23,6 +23,7 @@
#include <stdint.h>
#include "event-parse.h"
#include "trace-seq.h"
#ifdef HAVE_UDIS86
@ -248,7 +249,7 @@ static const char *find_exit_reason(unsigned isa, int val)
}
static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
struct event_format *event, const char *field)
struct tep_event_format *event, const char *field)
{
unsigned long long isa;
unsigned long long val;
@ -269,7 +270,7 @@ static int print_exit_reason(struct trace_seq *s, struct tep_record *record,
}
static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
unsigned long long info1 = 0, info2 = 0;
@ -292,7 +293,7 @@ static int kvm_exit_handler(struct trace_seq *s, struct tep_record *record,
static int kvm_emulate_insn_handler(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
unsigned long long rip, csbase, len, flags, failed;
int llen;
@ -331,7 +332,7 @@ static int kvm_emulate_insn_handler(struct trace_seq *s,
static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
if (print_exit_reason(s, record, event, "exit_code") < 0)
return -1;
@ -345,7 +346,7 @@ static int kvm_nested_vmexit_inject_handler(struct trace_seq *s, struct tep_reco
}
static int kvm_nested_vmexit_handler(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
tep_print_num_field(s, "rip %llx ", event, "rip", record, 1);
@ -371,7 +372,7 @@ union kvm_mmu_page_role {
};
static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
unsigned long long val;
static const char *access_str[] = {
@ -418,7 +419,7 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct tep_record *record,
static int kvm_mmu_get_page_handler(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
unsigned long long val;

View file

@ -22,13 +22,14 @@
#include <string.h>
#include "event-parse.h"
#include "trace-seq.h"
#define INDENT 65
static void print_string(struct trace_seq *s, struct event_format *event,
static void print_string(struct trace_seq *s, struct tep_event_format *event,
const char *name, const void *data)
{
struct format_field *f = tep_find_field(event, name);
struct tep_format_field *f = tep_find_field(event, name);
int offset;
int length;
@ -59,7 +60,7 @@ static void print_string(struct trace_seq *s, struct event_format *event,
static int drv_bss_info_changed(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
void *data = record->data;

View file

@ -22,6 +22,7 @@
#include <string.h>
#include "event-parse.h"
#include "trace-seq.h"
static void write_state(struct trace_seq *s, int val)
{
@ -44,7 +45,7 @@ static void write_state(struct trace_seq *s, int val)
trace_seq_putc(s, 'R');
}
static void write_and_save_comm(struct format_field *field,
static void write_and_save_comm(struct tep_format_field *field,
struct tep_record *record,
struct trace_seq *s, int pid)
{
@ -66,9 +67,9 @@ static void write_and_save_comm(struct format_field *field,
static int sched_wakeup_handler(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
struct format_field *field;
struct tep_format_field *field;
unsigned long long val;
if (tep_get_field_val(s, event, "pid", record, &val, 1))
@ -95,9 +96,9 @@ static int sched_wakeup_handler(struct trace_seq *s,
static int sched_switch_handler(struct trace_seq *s,
struct tep_record *record,
struct event_format *event, void *context)
struct tep_event_format *event, void *context)
{
struct format_field *field;
struct tep_format_field *field;
unsigned long long val;
if (tep_get_field_val(s, event, "prev_pid", record, &val, 1))

View file

@ -3,6 +3,7 @@
#include <string.h>
#include <inttypes.h>
#include "event-parse.h"
#include "trace-seq.h"
typedef unsigned long sector_t;
typedef uint64_t u64;

View file

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include "event-parse.h"
#include "trace-seq.h"
#define __HYPERVISOR_set_trap_table 0
#define __HYPERVISOR_mmu_update 1

View file

@ -0,0 +1,53 @@
// SPDX-License-Identifier: LGPL-2.1
#undef _GNU_SOURCE
#include <string.h>
#include <stdio.h>
#include "event-parse.h"
#undef _PE
#define _PE(code, str) str
static const char * const tep_error_str[] = {
TEP_ERRORS
};
#undef _PE
/*
* The tools so far have been using the strerror_r() GNU variant, that returns
* a string, be it the buffer passed or something else.
*
* But that, besides being tricky in cases where we expect that the function
* using strerror_r() returns the error formatted in a provided buffer (we have
* to check if it returned something else and copy that instead), breaks the
* build on systems not using glibc, like Alpine Linux, where musl libc is
* used.
*
* So, introduce yet another wrapper, str_error_r(), that has the GNU
* interface, but uses the portable XSI variant of strerror_r(), so that users
* rest asured that the provided buffer is used and it is what is returned.
*/
int tep_strerror(struct tep_handle *tep __maybe_unused,
enum tep_errno errnum, char *buf, size_t buflen)
{
const char *msg;
int idx;
if (!buflen)
return 0;
if (errnum >= 0) {
int err = strerror_r(errnum, buf, buflen);
buf[buflen - 1] = 0;
return err;
}
if (errnum <= __TEP_ERRNO__START ||
errnum >= __TEP_ERRNO__END)
return -1;
idx = errnum - __TEP_ERRNO__START - 1;
msg = tep_error_str[idx];
snprintf(buf, buflen, "%s", msg);
return 0;
}

View file

@ -3,6 +3,8 @@
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
*/
#include "trace-seq.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

View file

@ -0,0 +1,55 @@
// SPDX-License-Identifier: LGPL-2.1
/*
* Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
*/
#ifndef _TRACE_SEQ_H
#define _TRACE_SEQ_H
#include <stdarg.h>
#include <stdio.h>
/* ----------------------- trace_seq ----------------------- */
#ifndef TRACE_SEQ_BUF_SIZE
#define TRACE_SEQ_BUF_SIZE 4096
#endif
enum trace_seq_fail {
TRACE_SEQ__GOOD,
TRACE_SEQ__BUFFER_POISONED,
TRACE_SEQ__MEM_ALLOC_FAILED,
};
/*
* Trace sequences are used to allow a function to call several other functions
* to create a string of data to use (up to a max of PAGE_SIZE).
*/
struct trace_seq {
char *buffer;
unsigned int buffer_size;
unsigned int len;
unsigned int readpos;
enum trace_seq_fail state;
};
void trace_seq_init(struct trace_seq *s);
void trace_seq_reset(struct trace_seq *s);
void trace_seq_destroy(struct trace_seq *s);
extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
__attribute__ ((format (printf, 2, 0)));
extern int trace_seq_puts(struct trace_seq *s, const char *str);
extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
extern void trace_seq_terminate(struct trace_seq *s);
extern int trace_seq_do_fprintf(struct trace_seq *s, FILE *fp);
extern int trace_seq_do_printf(struct trace_seq *s);
#endif /* _TRACE_SEQ_H */