Blame source/vdo/base/trace.h

Packit Service 75d76b
/*
Packit Service 75d76b
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service 75d76b
 *
Packit Service 75d76b
 * This program is free software; you can redistribute it and/or
Packit Service 75d76b
 * modify it under the terms of the GNU General Public License
Packit Service 75d76b
 * as published by the Free Software Foundation; either version 2
Packit Service 75d76b
 * of the License, or (at your option) any later version.
Packit Service 75d76b
 * 
Packit Service 75d76b
 * This program is distributed in the hope that it will be useful,
Packit Service 75d76b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 75d76b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 75d76b
 * GNU General Public License for more details.
Packit Service 75d76b
 * 
Packit Service 75d76b
 * You should have received a copy of the GNU General Public License
Packit Service 75d76b
 * along with this program; if not, write to the Free Software
Packit Service 75d76b
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 75d76b
 * 02110-1301, USA. 
Packit Service 75d76b
 *
Packit Service 75d76b
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/trace.h#1 $
Packit Service 75d76b
 */
Packit Service 75d76b
Packit Service 75d76b
#ifndef TRACE_H
Packit Service 75d76b
#define TRACE_H
Packit Service 75d76b
Packit Service 75d76b
#ifndef __KERNEL__
Packit Service 75d76b
#include "cpu.h"
Packit Service 75d76b
#endif
Packit Service 75d76b
Packit Service 75d76b
#include "threads.h"
Packit Service 75d76b
Packit Service 75d76b
/*
Packit Service 75d76b
 * We need these records to be glued together with no intervening
Packit Service 75d76b
 * bytes. That makes it rather sensitive to how the compiler,
Packit Service 75d76b
 * assembler, and linker may add padding. Force extra alignment to
Packit Service 75d76b
 * make it more reliable.
Packit Service 75d76b
 *
Packit Service 75d76b
 * Trace point descriptor language:
Packit Service 75d76b
 *
Packit Service 75d76b
 * The descriptor string provided at a trace point can have one or
Packit Service 75d76b
 * more components, separated by ";". The first (or only) component is
Packit Service 75d76b
 * a string to be formatted and shown in the flowchart graph. The
Packit Service 75d76b
 * remaining components must be of the form "var=string", and assign
Packit Service 75d76b
 * string values to "variables" that last through the processing of
Packit Service 75d76b
 * the remainder of the current trace being read.
Packit Service 75d76b
 *
Packit Service 75d76b
 * The string displayed has variable substitutions done for any
Packit Service 75d76b
 * occurrences of "$var" in the string.
Packit Service 75d76b
 *
Packit Service 75d76b
 * So, the descriptor sequence:
Packit Service 75d76b
 *   kvdoWriteVIO;io=writeData;j=normal
Packit Service 75d76b
 *   submitBio($io)
Packit Service 75d76b
 *   writeJournalBlock($j)
Packit Service 75d76b
 * would cause the graph generator to show the strings:
Packit Service 75d76b
 *   kvdoWriteVIO
Packit Service 75d76b
 *   submitBio(writeData)
Packit Service 75d76b
 *   writeJournalBlock(normal)
Packit Service 75d76b
 *
Packit Service 75d76b
 * Substitutions are done in the variable assignment strings when
Packit Service 75d76b
 * they're processed, so "foo=x($bar)" sets "foo" using the current
Packit Service 75d76b
 * value of "bar"; it doesn't cause "bar" to be looked up when "$foo"
Packit Service 75d76b
 * is seen later.
Packit Service 75d76b
 *
Packit Service 75d76b
 * The variable named "F" is automatically updated with the name of
Packit Service 75d76b
 * the function associated with the descriptor, so you don't have to
Packit Service 75d76b
 * explicitly repeat the name of the function if you just want to
Packit Service 75d76b
 * augment it with more information. This may be desirable if a trace
Packit Service 75d76b
 * point is expected to be reached more than once at different stages
Packit Service 75d76b
 * of processing, or in a static function with a generic-sounding name
Packit Service 75d76b
 * that needs disambiguation for graphing.
Packit Service 75d76b
 *
Packit Service 75d76b
 * If no descriptor string is provided, the
Packit Service 75d76b
 * function:lineNumber:threadName string reported via systemtap will
Packit Service 75d76b
 * be used in the graph.
Packit Service 75d76b
 *
Packit Service 75d76b
 * Current variable names used:
Packit Service 75d76b
 *   cb=(various)      random info to log when enqueueing VIO callback
Packit Service 75d76b
 *   dup=post,update   deduplication operation
Packit Service 75d76b
 *   io=(various)      kind of I/O and data it's being done on
Packit Service 75d76b
 *   j=normal,dedupe   kind of journal update being done
Packit Service 75d76b
 *   js=mapWrite,writeZero,unmap  which step of journaling we're doing
Packit Service 75d76b
 */
Packit Service 75d76b
typedef const struct __attribute__((aligned(16))) traceLocationRecord {
Packit Service 75d76b
  const char *function;
Packit Service 75d76b
  int         line;
Packit Service 75d76b
  const char *description;
Packit Service 75d76b
} TraceLocationRecord;
Packit Service 75d76b
Packit Service 75d76b
/*
Packit Service 75d76b
 * With well under 100 locations defined at the moment, even with no
Packit Service 75d76b
 * idea where &baseTraceLocation will fall relative to the others, we
Packit Service 75d76b
 * only need to support a range of -100..+100.
Packit Service 75d76b
 */
Packit Service 75d76b
typedef int32_t TraceLocationNumber;
Packit Service 75d76b
Packit Service 75d76b
/* The type to pass around */
Packit Service 75d76b
typedef TraceLocationRecord *TraceLocation;
Packit Service 75d76b
Packit Service 75d76b
/*
Packit Service 75d76b
 * N.B.: This code uses GCC extensions to create static, initialized
Packit Service 75d76b
 * objects inline, describing the current function and line number.
Packit Service 75d76b
 * The objects are collected into a table we can index with small
Packit Service 75d76b
 * signed integers relative to &baseTraceLocation.
Packit Service 75d76b
 *
Packit Service 75d76b
 * We need baseTraceLocation because there's no standard way to get
Packit Service 75d76b
 * the address of the start of this array we're defining.  And because
Packit Service 75d76b
 * we're not playing any (additional) special linker tricks to ensure
Packit Service 75d76b
 * ordering of the object files, the offsets may be signed, and we
Packit Service 75d76b
 * don't know the range beyond the fact that we don't have hundreds of
Packit Service 75d76b
 * these records lying around.
Packit Service 75d76b
 *
Packit Service 75d76b
 * By specifying a name that starts with neither .data nor .rodata, we
Packit Service 75d76b
 * leave it to the toolchain to pick a location for us, based on
Packit Service 75d76b
 * things like whether the section needs write access, which it does
Packit Service 75d76b
 * for a PIC library but not for a kernel module.
Packit Service 75d76b
 */
Packit Service 75d76b
Packit Service 75d76b
#define TRACE_LOCATION_SECTION \
Packit Service 75d76b
  __attribute__((section(".kvdo_trace_locations")))
Packit Service 75d76b
Packit Service 75d76b
extern TRACE_LOCATION_SECTION TraceLocationRecord baseTraceLocation[];
Packit Service 75d76b
Packit Service 75d76b
#define TRACE_JOIN2(a,b) a##b
Packit Service 75d76b
#define TRACE_JOIN(a,b) TRACE_JOIN2(a,b)
Packit Service 75d76b
#define THIS_LOCATION(DESCRIPTION)                                      \
Packit Service 75d76b
  __extension__                                                         \
Packit Service 75d76b
  ({                                                                    \
Packit Service 75d76b
    static TRACE_LOCATION_SECTION                                       \
Packit Service 75d76b
      TraceLocationRecord TRACE_JOIN(loc,__LINE__) = {                  \
Packit Service 75d76b
      .function    = __func__,                                          \
Packit Service 75d76b
      .line        = __LINE__,                                          \
Packit Service 75d76b
      .description = DESCRIPTION,                                       \
Packit Service 75d76b
    };                                                                  \
Packit Service 75d76b
    &TRACE_JOIN(loc,__LINE__);                                          \
Packit Service 75d76b
  })
Packit Service 75d76b
Packit Service 75d76b
typedef struct traceRecord {
Packit Service 75d76b
  uint64_t            when;     // counted in usec
Packit Service 75d76b
  pid_t               tid;
Packit Service 75d76b
  TraceLocationNumber location;
Packit Service 75d76b
} TraceRecord;
Packit Service 75d76b
Packit Service 75d76b
enum { NUM_TRACE_RECORDS = 71 };
Packit Service 75d76b
Packit Service 75d76b
typedef struct trace {
Packit Service 75d76b
  unsigned int used;
Packit Service 75d76b
  TraceRecord  records[NUM_TRACE_RECORDS];
Packit Service 75d76b
} Trace;
Packit Service 75d76b
Packit Service 75d76b
/**
Packit Service 75d76b
 * Store a new record in the trace data.
Packit Service 75d76b
 *
Packit Service 75d76b
 * @param trace    The trace data to be updated
Packit Service 75d76b
 * @param location The source-location descriptor to be recorded
Packit Service 75d76b
 **/
Packit Service 75d76b
void addTraceRecord(Trace *trace, TraceLocation location);
Packit Service 75d76b
Packit Service 75d76b
/**
Packit Service 75d76b
 * Format trace data into a string for logging.
Packit Service 75d76b
 *
Packit Service 75d76b
 * @param [in]  trace         The trace data to be logged
Packit Service 75d76b
 * @param [in]  buffer        The buffer in which to store the string
Packit Service 75d76b
 * @param [in]  bufferLength  Length of the buffer
Packit Service 75d76b
 * @param [out] msgLen        Length of the formatted string
Packit Service 75d76b
 **/
Packit Service 75d76b
void formatTrace(Trace  *trace,
Packit Service 75d76b
                 char   *buffer,
Packit Service 75d76b
                 size_t  bufferLength,
Packit Service 75d76b
                 size_t *msgLen);
Packit Service 75d76b
Packit Service 75d76b
#endif /* TRACE_H */