2015-12-08 15:45:58 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2015 Cisco and/or its affiliates.
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at:
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
Copyright (c) 2005,2009 Eliot Dresselhaus
|
|
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
a copy of this software and associated documentation files (the
|
|
|
|
|
"Software"), to deal in the Software without restriction, including
|
|
|
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
the following conditions:
|
|
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
|
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/* High speed event logger */
|
|
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
The fine-grained event logger allows lightweight, thread-safe
|
|
|
|
|
event logging at minimum cost. In typical operation, logging
|
|
|
|
|
a single event costs around 80ns on x86_64. It's appropriate
|
|
|
|
|
for at-least per-frame event-logging in vector packet processing.
|
|
|
|
|
|
|
|
|
|
See https://wiki.fd.io/view/VPP/elog for more information.
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
#ifndef included_clib_elog_h
|
|
|
|
|
#define included_clib_elog_h
|
|
|
|
|
|
|
|
|
|
#include <vppinfra/cache.h>
|
2016-08-15 11:12:27 -04:00
|
|
|
#include <vppinfra/error.h> /* for ASSERT */
|
2015-12-08 15:45:58 -07:00
|
|
|
#include <vppinfra/serialize.h>
|
2016-08-15 11:12:27 -04:00
|
|
|
#include <vppinfra/time.h> /* for clib_cpu_time_now */
|
2019-06-14 12:02:38 -04:00
|
|
|
#include <vppinfra/hash.h>
|
2015-12-08 15:45:58 -07:00
|
|
|
#include <vppinfra/mhash.h>
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
union
|
|
|
|
|
{
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Absolute time stamp in CPU clock cycles. */
|
2015-12-08 15:45:58 -07:00
|
|
|
u64 time_cycles;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Absolute time as floating point number in seconds. */
|
2015-12-08 15:45:58 -07:00
|
|
|
f64 time;
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Event type index. */
|
2020-08-19 06:59:53 -04:00
|
|
|
u16 event_type;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Track for this event. Tracks allow events to be sorted and
|
2015-12-08 15:45:58 -07:00
|
|
|
displayed by track. Think of 2 dimensional display with time and
|
2016-08-15 11:12:27 -04:00
|
|
|
track being the x and y axes. */
|
2015-12-08 15:45:58 -07:00
|
|
|
u16 track;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** 20-bytes of data follows, pads to 32 bytes. */
|
2015-12-08 15:45:58 -07:00
|
|
|
u8 data[20];
|
|
|
|
|
} elog_event_t;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
|
{
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Type index plus one assigned to this type.
|
2015-12-08 15:45:58 -07:00
|
|
|
This is used to mark type as seen. */
|
|
|
|
|
u32 type_index_plus_one;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** String table as a vector constructed when type is registered. */
|
2016-08-15 11:12:27 -04:00
|
|
|
char **enum_strings_vector;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Format string. (example: "my-event (%d,%d)"). */
|
2016-08-15 11:12:27 -04:00
|
|
|
char *format;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Specifies how arguments to format are parsed from event data.
|
2015-12-08 15:45:58 -07:00
|
|
|
String of characters '0' '1' or '2' '3' to specify log2 size of data
|
|
|
|
|
(e.g. for u8, u16, u32 or u64),
|
|
|
|
|
's' means a null-terminated C string
|
|
|
|
|
't' means argument is an index into enum string table for this type.
|
|
|
|
|
'e' is a float,
|
|
|
|
|
'f' is a double. */
|
2016-08-15 11:12:27 -04:00
|
|
|
char *format_args;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Function name generating event. */
|
2016-08-15 11:12:27 -04:00
|
|
|
char *function;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Number of elements in string enum table. */
|
2015-12-08 15:45:58 -07:00
|
|
|
u32 n_enum_strings;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** String table for enum/number to string formatting. */
|
2016-08-15 11:12:27 -04:00
|
|
|
char *enum_strings[];
|
2015-12-08 15:45:58 -07:00
|
|
|
} elog_event_type_t;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
|
{
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Track name vector. */
|
2016-08-15 11:12:27 -04:00
|
|
|
char *name;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Set to one when track has been added to
|
2015-12-08 15:45:58 -07:00
|
|
|
main structure. */
|
|
|
|
|
u32 track_index_plus_one;
|
|
|
|
|
} elog_track_t;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
|
{
|
2017-04-01 11:07:40 -04:00
|
|
|
/** CPU cycle counter. */
|
2015-12-08 15:45:58 -07:00
|
|
|
u64 cpu;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** OS timer in nano secs since epoch 3/30/2017, see elog_time_now() */
|
2015-12-08 15:45:58 -07:00
|
|
|
u64 os_nsec;
|
|
|
|
|
} elog_time_stamp_t;
|
|
|
|
|
|
2016-08-15 11:12:27 -04:00
|
|
|
typedef struct
|
|
|
|
|
{
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Total number of events in buffer. */
|
2015-12-08 15:45:58 -07:00
|
|
|
u32 n_total_events;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** When count reaches limit logging is disabled. This is
|
2015-12-08 15:45:58 -07:00
|
|
|
used for event triggers. */
|
|
|
|
|
u32 n_total_events_disable_limit;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Dummy event to use when logger is disabled. */
|
2020-08-06 12:10:09 -04:00
|
|
|
elog_event_t placeholder_event;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Power of 2 number of elements in ring. */
|
2015-12-08 15:45:58 -07:00
|
|
|
uword event_ring_size;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Vector of events (circular buffer). Power of 2 size.
|
|
|
|
|
Used when events are being collected. */
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_event_t *event_ring;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Vector of event types. */
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_event_type_t *event_types;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Hash table mapping type format to type index. */
|
2016-08-15 11:12:27 -04:00
|
|
|
uword *event_type_by_format;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Events may refer to strings in string table. */
|
2016-08-15 11:12:27 -04:00
|
|
|
char *string_table;
|
2019-06-14 12:02:38 -04:00
|
|
|
uword *string_table_hash;
|
|
|
|
|
u8 *string_table_tmp;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Vector of tracks. */
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_track_t *tracks;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Default track. */
|
2015-12-08 15:45:58 -07:00
|
|
|
elog_track_t default_track;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Place holder for CPU clock frequency. */
|
2015-12-08 15:45:58 -07:00
|
|
|
clib_time_t cpu_timer;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Timestamps */
|
2015-12-08 15:45:58 -07:00
|
|
|
elog_time_stamp_t init_time, serialize_time;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** SMP lock, non-zero means locking required */
|
2016-08-15 11:12:27 -04:00
|
|
|
uword *lock;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Use serialize_time and init_time to give estimate for
|
|
|
|
|
cpu clock frequency. */
|
2015-12-08 15:45:58 -07:00
|
|
|
f64 nsec_per_cpu_clock;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** Vector of events converted to generic form after collection. */
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_event_t *events;
|
2015-12-08 15:45:58 -07:00
|
|
|
} elog_main_t;
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Return number of events in the event-log buffer
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@return number of events in the buffer
|
|
|
|
|
*/
|
|
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline uword
|
|
|
|
|
elog_n_events_in_buffer (elog_main_t * em)
|
2016-08-15 11:12:27 -04:00
|
|
|
{
|
|
|
|
|
return clib_min (em->n_total_events, em->event_ring_size);
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Return number of events which can fit in the event buffer
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@return number of events which can fit in the buffer
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline uword
|
|
|
|
|
elog_buffer_capacity (elog_main_t * em)
|
2016-08-15 11:12:27 -04:00
|
|
|
{
|
|
|
|
|
return em->event_ring_size;
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Reset the event buffer
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void
|
|
|
|
|
elog_reset_buffer (elog_main_t * em)
|
|
|
|
|
{
|
|
|
|
|
em->n_total_events = 0;
|
|
|
|
|
em->n_total_events_disable_limit = ~0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Enable or disable event logging
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void
|
|
|
|
|
elog_enable_disable (elog_main_t * em, int is_enabled)
|
|
|
|
|
{
|
|
|
|
|
em->n_total_events = 0;
|
2015-12-18 10:26:56 +01:00
|
|
|
em->n_total_events_disable_limit = is_enabled ? ~0 : 0;
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief disable logging after specified number of ievents have been logged.
|
|
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
This is used as a "debug trigger" when a certain event has occurred.
|
|
|
|
|
Events will be logged both before and after the "event" but the
|
2017-04-01 11:07:40 -04:00
|
|
|
event will not be lost as long as N < RING_SIZE.
|
|
|
|
|
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param n uword number of events before disabling event logging
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void
|
|
|
|
|
elog_disable_after_events (elog_main_t * em, uword n)
|
2016-08-15 11:12:27 -04:00
|
|
|
{
|
|
|
|
|
em->n_total_events_disable_limit = em->n_total_events + n;
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/* @brief mid-buffer logic-analyzer trigger
|
|
|
|
|
|
|
|
|
|
Currently, only midpoint triggering is supported, but it's pretty obvious
|
|
|
|
|
how to generalize the scheme.
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void
|
|
|
|
|
elog_disable_trigger (elog_main_t * em)
|
2016-08-15 11:12:27 -04:00
|
|
|
{
|
|
|
|
|
em->n_total_events_disable_limit =
|
|
|
|
|
em->n_total_events + vec_len (em->event_ring) / 2;
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief register an event type
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param t elog_event_type_t * event to register
|
|
|
|
|
@return type index
|
|
|
|
|
@warning Typically not called directly
|
|
|
|
|
*/
|
|
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
word elog_event_type_register (elog_main_t * em, elog_event_type_t * t);
|
2017-04-01 11:07:40 -04:00
|
|
|
|
|
|
|
|
/** @brief register an event track
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param t elog_track_t * track to register
|
|
|
|
|
@return track index
|
|
|
|
|
@note this function is often called directly
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
word elog_track_register (elog_main_t * em, elog_track_t * t);
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief event logging enabled predicate
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@return 1 if enabled, 0 if not enabled
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline uword
|
|
|
|
|
elog_is_enabled (elog_main_t * em)
|
2016-08-15 11:12:27 -04:00
|
|
|
{
|
|
|
|
|
return em->n_total_events < em->n_total_events_disable_limit;
|
|
|
|
|
}
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Allocate an event to be filled in by the caller
|
|
|
|
|
|
|
|
|
|
Not normally called directly; this function underlies the
|
|
|
|
|
ELOG_DATA and ELOG_TRACK_DATA macros
|
|
|
|
|
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param type elog_event_type_t * type
|
|
|
|
|
@param track elog_track_t * track
|
|
|
|
|
@param cpu_time u64 current cpu tick value
|
|
|
|
|
@returns event to be filled in
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void *
|
|
|
|
|
elog_event_data_inline (elog_main_t * em,
|
|
|
|
|
elog_event_type_t * type,
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_track_t * track, u64 cpu_time)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_event_t *e;
|
2015-12-08 15:45:58 -07:00
|
|
|
uword ei;
|
|
|
|
|
word type_index, track_index;
|
|
|
|
|
|
2020-08-06 12:10:09 -04:00
|
|
|
/* Return the user placeholder memory to scribble data into. */
|
2016-08-15 11:12:27 -04:00
|
|
|
if (PREDICT_FALSE (!elog_is_enabled (em)))
|
2020-08-06 12:10:09 -04:00
|
|
|
return em->placeholder_event.data;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
type_index = (word) type->type_index_plus_one - 1;
|
|
|
|
|
track_index = (word) track->track_index_plus_one - 1;
|
|
|
|
|
if (PREDICT_FALSE ((type_index | track_index) < 0))
|
|
|
|
|
{
|
|
|
|
|
if (type_index < 0)
|
|
|
|
|
type_index = elog_event_type_register (em, type);
|
|
|
|
|
if (track_index < 0)
|
|
|
|
|
track_index = elog_track_register (em, track);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASSERT (track_index < vec_len (em->tracks));
|
|
|
|
|
ASSERT (is_pow2 (vec_len (em->event_ring)));
|
|
|
|
|
|
|
|
|
|
if (em->lock)
|
2018-10-03 22:53:51 +00:00
|
|
|
ei = clib_atomic_fetch_add (&em->n_total_events, 1);
|
2015-12-08 15:45:58 -07:00
|
|
|
else
|
|
|
|
|
ei = em->n_total_events++;
|
|
|
|
|
|
|
|
|
|
ei &= em->event_ring_size - 1;
|
|
|
|
|
e = vec_elt_at_index (em->event_ring, ei);
|
|
|
|
|
|
|
|
|
|
e->time_cycles = cpu_time;
|
2020-08-19 06:59:53 -04:00
|
|
|
e->event_type = type_index;
|
2015-12-08 15:45:58 -07:00
|
|
|
e->track = track_index;
|
|
|
|
|
|
|
|
|
|
/* Return user data for caller to fill in. */
|
|
|
|
|
return e->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* External version of inline. */
|
2016-08-15 11:12:27 -04:00
|
|
|
void *elog_event_data (elog_main_t * em,
|
|
|
|
|
elog_event_type_t * type,
|
|
|
|
|
elog_track_t * track, u64 cpu_time);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Allocate an event to be filled in by the caller, non-inline
|
|
|
|
|
|
|
|
|
|
Not normally called directly; this function underlies the
|
|
|
|
|
ELOG_DATA and ELOG_TRACK_DATA macros
|
|
|
|
|
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param type elog_event_type_t * type
|
|
|
|
|
@param track elog_track_t * track
|
|
|
|
|
@param cpu_time u64 current cpu tick value
|
|
|
|
|
@returns event to be filled in
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void *
|
|
|
|
|
elog_event_data_not_inline (elog_main_t * em,
|
|
|
|
|
elog_event_type_t * type,
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_track_t * track, u64 cpu_time)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2020-08-06 12:10:09 -04:00
|
|
|
/* Return the user placeholder memory to scribble data into. */
|
2016-08-15 11:12:27 -04:00
|
|
|
if (PREDICT_FALSE (!elog_is_enabled (em)))
|
2020-08-06 12:10:09 -04:00
|
|
|
return em->placeholder_event.data;
|
2015-12-08 15:45:58 -07:00
|
|
|
return elog_event_data (em, type, track, cpu_time);
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Log a single-datum event
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param type elog_event_type_t * type
|
|
|
|
|
@param data u32 single datum to capture
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void
|
|
|
|
|
elog (elog_main_t * em, elog_event_type_t * type, u32 data)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *d = elog_event_data_not_inline (em,
|
|
|
|
|
type,
|
|
|
|
|
&em->default_track,
|
|
|
|
|
clib_cpu_time_now ());
|
2015-12-08 15:45:58 -07:00
|
|
|
d[0] = data;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Log a single-datum event, inline version
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param type elog_event_type_t * type
|
|
|
|
|
@param data u32 single datum to capture
|
|
|
|
|
*/
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void
|
|
|
|
|
elog_inline (elog_main_t * em, elog_event_type_t * type, u32 data)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *d = elog_event_data_inline (em,
|
|
|
|
|
type,
|
|
|
|
|
&em->default_track,
|
|
|
|
|
clib_cpu_time_now ());
|
2015-12-08 15:45:58 -07:00
|
|
|
d[0] = data;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Log a single-datum event to a specific track, non-inline version
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param type elog_event_type_t * type
|
|
|
|
|
@param type elog_event_track_t * track
|
|
|
|
|
@param data u32 single datum to capture
|
|
|
|
|
*/
|
2016-03-26 18:45:42 -04:00
|
|
|
always_inline void
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_track (elog_main_t * em, elog_event_type_t * type, elog_track_t * track,
|
|
|
|
|
u32 data)
|
2016-03-26 18:45:42 -04:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *d = elog_event_data_not_inline (em,
|
|
|
|
|
type,
|
|
|
|
|
track,
|
|
|
|
|
clib_cpu_time_now ());
|
2016-03-26 18:45:42 -04:00
|
|
|
d[0] = data;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief Log a single-datum event to a specific track
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param type elog_event_type_t * type
|
|
|
|
|
@param type elog_event_track_t * track
|
|
|
|
|
@param data u32 single datum to capture
|
|
|
|
|
*/
|
2016-03-26 18:45:42 -04:00
|
|
|
always_inline void
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_track_inline (elog_main_t * em, elog_event_type_t * type,
|
|
|
|
|
elog_track_t * track, u32 data)
|
2016-03-26 18:45:42 -04:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 *d = elog_event_data_inline (em,
|
|
|
|
|
type,
|
|
|
|
|
track,
|
|
|
|
|
clib_cpu_time_now ());
|
2016-03-26 18:45:42 -04:00
|
|
|
d[0] = data;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline void *
|
|
|
|
|
elog_data (elog_main_t * em, elog_event_type_t * type, elog_track_t * track)
|
|
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
return elog_event_data_not_inline (em, type, track, clib_cpu_time_now ());
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
always_inline void *
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_data_inline (elog_main_t * em, elog_event_type_t * type,
|
|
|
|
|
elog_track_t * track)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
2016-08-15 11:12:27 -04:00
|
|
|
return elog_event_data_inline (em, type, track, clib_cpu_time_now ());
|
2015-12-08 15:45:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Macro shorthands for generating/declaring events. */
|
|
|
|
|
#define __ELOG_TYPE_VAR(f) f
|
|
|
|
|
#define __ELOG_TRACK_VAR(f) f
|
|
|
|
|
|
|
|
|
|
#define ELOG_TYPE_DECLARE(f) static elog_event_type_t __ELOG_TYPE_VAR(f)
|
|
|
|
|
|
|
|
|
|
#define ELOG_TYPE_INIT_FORMAT_AND_FUNCTION(fmt,func) \
|
|
|
|
|
{ .format = fmt, .function = func, }
|
|
|
|
|
|
|
|
|
|
#define ELOG_TYPE_INIT(fmt) \
|
|
|
|
|
ELOG_TYPE_INIT_FORMAT_AND_FUNCTION(fmt,(char *) __FUNCTION__)
|
|
|
|
|
|
|
|
|
|
#define ELOG_TYPE_DECLARE_HELPER(f,fmt,func) \
|
|
|
|
|
static elog_event_type_t __ELOG_TYPE_VAR(f) = \
|
|
|
|
|
ELOG_TYPE_INIT_FORMAT_AND_FUNCTION (fmt, func)
|
|
|
|
|
|
|
|
|
|
#define ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION(f,fmt) \
|
|
|
|
|
ELOG_TYPE_DECLARE_HELPER (f, fmt, (char *) __FUNCTION__)
|
|
|
|
|
|
|
|
|
|
#define ELOG_TYPE_DECLARE_FORMAT(f,fmt) \
|
|
|
|
|
ELOG_TYPE_DECLARE_HELPER (f, fmt, 0)
|
|
|
|
|
|
|
|
|
|
/* Shorthands with and without __FUNCTION__.
|
|
|
|
|
D for decimal; X for hex. F for __FUNCTION__. */
|
|
|
|
|
#define ELOG_TYPE(f,fmt) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION(f,fmt)
|
|
|
|
|
#define ELOG_TYPE_D(f) ELOG_TYPE_DECLARE_FORMAT (f, #f " %d")
|
|
|
|
|
#define ELOG_TYPE_X(f) ELOG_TYPE_DECLARE_FORMAT (f, #f " 0x%x")
|
|
|
|
|
#define ELOG_TYPE_DF(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " %d")
|
|
|
|
|
#define ELOG_TYPE_XF(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " 0x%x")
|
|
|
|
|
#define ELOG_TYPE_FD(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " %d")
|
|
|
|
|
#define ELOG_TYPE_FX(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " 0x%x")
|
|
|
|
|
|
|
|
|
|
#define ELOG_TRACK_DECLARE(f) static elog_track_t __ELOG_TRACK_VAR(f)
|
|
|
|
|
#define ELOG_TRACK(f) ELOG_TRACK_DECLARE(f) = { .name = #f, }
|
|
|
|
|
|
|
|
|
|
/* Log 32 bits of data. */
|
|
|
|
|
#define ELOG(em,f,data) elog ((em), &__ELOG_TYPE_VAR(f), data)
|
|
|
|
|
#define ELOG_INLINE(em,f,data) elog_inline ((em), &__ELOG_TYPE_VAR(f), data)
|
|
|
|
|
|
|
|
|
|
/* Return data pointer to fill in. */
|
|
|
|
|
#define ELOG_TRACK_DATA(em,f,track) \
|
|
|
|
|
elog_data ((em), &__ELOG_TYPE_VAR(f), &__ELOG_TRACK_VAR(track))
|
|
|
|
|
#define ELOG_TRACK_DATA_INLINE(em,f,track) \
|
|
|
|
|
elog_data_inline ((em), &__ELOG_TYPE_VAR(f), &__ELOG_TRACK_VAR(track))
|
|
|
|
|
|
|
|
|
|
/* Shorthand with default track. */
|
|
|
|
|
#define ELOG_DATA(em,f) elog_data ((em), &__ELOG_TYPE_VAR (f), &(em)->default_track)
|
|
|
|
|
#define ELOG_DATA_INLINE(em,f) elog_data_inline ((em), &__ELOG_TYPE_VAR (f), &(em)->default_track)
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief add a string to the event-log string table
|
|
|
|
|
|
|
|
|
|
Often combined with hashing and the T4 elog format specifier to
|
|
|
|
|
display complex strings in offline tooling
|
|
|
|
|
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@param format char *
|
|
|
|
|
@param VARARGS
|
|
|
|
|
@return u32 index to add to event log
|
|
|
|
|
*/
|
2016-08-15 11:12:27 -04:00
|
|
|
u32 elog_string (elog_main_t * em, char *format, ...);
|
2017-04-01 11:07:40 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
void elog_time_now (elog_time_stamp_t * et);
|
|
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief convert event ring events to events, and return them as a vector.
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@return event vector with timestamps in f64 seconds
|
|
|
|
|
@note sets em->events to resulting vector.
|
|
|
|
|
*/
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_event_t *elog_get_events (elog_main_t * em);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-04-01 11:07:40 -04:00
|
|
|
/** @brief convert event ring events to events, and return them as a vector.
|
|
|
|
|
@param em elog_main_t *
|
|
|
|
|
@return event vector with timestamps in f64 seconds
|
|
|
|
|
@note no side effects
|
|
|
|
|
*/
|
2016-08-15 11:12:27 -04:00
|
|
|
elog_event_t *elog_peek_events (elog_main_t * em);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
/* Merge two logs, add supplied track tags. */
|
2016-08-15 11:12:27 -04:00
|
|
|
void elog_merge (elog_main_t * dst, u8 * dst_tag,
|
2017-04-01 11:07:40 -04:00
|
|
|
elog_main_t * src, u8 * src_tag, f64 align_tweak);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
/* 2 arguments elog_main_t and elog_event_t to format event or track name. */
|
2016-08-15 11:12:27 -04:00
|
|
|
u8 *format_elog_event (u8 * s, va_list * va);
|
2018-12-19 13:07:49 -08:00
|
|
|
u8 *format_elog_track_name (u8 * s, va_list * va);
|
|
|
|
|
u8 *format_elog_track (u8 * s, va_list * args);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
void serialize_elog_main (serialize_main_t * m, va_list * va);
|
|
|
|
|
void unserialize_elog_main (serialize_main_t * m, va_list * va);
|
|
|
|
|
|
|
|
|
|
void elog_init (elog_main_t * em, u32 n_events);
|
2016-03-28 17:12:19 -04:00
|
|
|
void elog_alloc (elog_main_t * em, u32 n_events);
|
2020-11-25 10:07:09 -05:00
|
|
|
void elog_resize (elog_main_t * em, u32 n_events);
|
2015-12-08 15:45:58 -07:00
|
|
|
|
|
|
|
|
#ifdef CLIB_UNIX
|
|
|
|
|
always_inline clib_error_t *
|
2017-09-10 15:04:27 -04:00
|
|
|
elog_write_file (elog_main_t * em, char *clib_file, int flush_ring)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
serialize_main_t m;
|
2016-08-15 11:12:27 -04:00
|
|
|
clib_error_t *error;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-09-10 15:04:27 -04:00
|
|
|
error = serialize_open_clib_file (&m, clib_file);
|
2015-12-08 15:45:58 -07:00
|
|
|
if (error)
|
|
|
|
|
return error;
|
2017-04-01 11:07:40 -04:00
|
|
|
error = serialize (&m, serialize_elog_main, em, flush_ring);
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!error)
|
2015-12-08 15:45:58 -07:00
|
|
|
serialize_close (&m);
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-19 06:59:53 -04:00
|
|
|
clib_error_t *elog_write_file_not_inline (elog_main_t * em, char *clib_file,
|
|
|
|
|
int flush_ring);
|
|
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
always_inline clib_error_t *
|
2017-09-10 15:04:27 -04:00
|
|
|
elog_read_file (elog_main_t * em, char *clib_file)
|
2015-12-08 15:45:58 -07:00
|
|
|
{
|
|
|
|
|
serialize_main_t m;
|
2016-08-15 11:12:27 -04:00
|
|
|
clib_error_t *error;
|
2015-12-08 15:45:58 -07:00
|
|
|
|
2017-09-10 15:04:27 -04:00
|
|
|
error = unserialize_open_clib_file (&m, clib_file);
|
2015-12-08 15:45:58 -07:00
|
|
|
if (error)
|
|
|
|
|
return error;
|
|
|
|
|
error = unserialize (&m, unserialize_elog_main, em);
|
2016-08-15 11:12:27 -04:00
|
|
|
if (!error)
|
2015-12-08 15:45:58 -07:00
|
|
|
unserialize_close (&m);
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-19 06:59:53 -04:00
|
|
|
clib_error_t *elog_read_file_not_inline (elog_main_t * em, char *clib_file);
|
2020-08-20 08:30:39 -04:00
|
|
|
char *format_one_elog_event (void *em_arg, void *ep_arg);
|
2020-08-19 06:59:53 -04:00
|
|
|
|
2015-12-08 15:45:58 -07:00
|
|
|
#endif /* CLIB_UNIX */
|
|
|
|
|
|
|
|
|
|
#endif /* included_clib_elog_h */
|
2016-08-15 11:12:27 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* fd.io coding-style-patch-verification: ON
|
|
|
|
|
*
|
|
|
|
|
* Local Variables:
|
|
|
|
|
* eval: (c-set-style "gnu")
|
|
|
|
|
* End:
|
|
|
|
|
*/
|