LCOV - code coverage report
Current view: top level - vppinfra - elog.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 33 57 57.9 %
Date: 2023-10-26 01:39:38 Functions: 6 11 54.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : /*
      16             :   Copyright (c) 2005,2009 Eliot Dresselhaus
      17             : 
      18             :   Permission is hereby granted, free of charge, to any person obtaining
      19             :   a copy of this software and associated documentation files (the
      20             :   "Software"), to deal in the Software without restriction, including
      21             :   without limitation the rights to use, copy, modify, merge, publish,
      22             :   distribute, sublicense, and/or sell copies of the Software, and to
      23             :   permit persons to whom the Software is furnished to do so, subject to
      24             :   the following conditions:
      25             : 
      26             :   The above copyright notice and this permission notice shall be
      27             :   included in all copies or substantial portions of the Software.
      28             : 
      29             :   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
      30             :   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      31             :   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      32             :   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      33             :   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
      34             :   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
      35             :   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      36             : */
      37             : 
      38             : /* High speed event logger */
      39             : 
      40             : /** \file
      41             :     The fine-grained event logger allows lightweight, thread-safe
      42             :     event logging at minimum cost. In typical operation, logging
      43             :     a single event costs around 80ns on x86_64. It's appropriate
      44             :     for at-least per-frame event-logging in vector packet processing.
      45             : 
      46             :     See https://wiki.fd.io/view/VPP/elog for more information.
      47             : */
      48             : 
      49             : #ifndef included_clib_elog_h
      50             : #define included_clib_elog_h
      51             : 
      52             : #include <vppinfra/cache.h>
      53             : #include <vppinfra/error.h>       /* for ASSERT */
      54             : #include <vppinfra/serialize.h>
      55             : #include <vppinfra/time.h>        /* for clib_cpu_time_now */
      56             : #include <vppinfra/hash.h>
      57             : #include <vppinfra/mhash.h>
      58             : 
      59             : typedef struct
      60             : {
      61             :   union
      62             :   {
      63             :     /** Absolute time stamp in CPU clock cycles. */
      64             :     u64 time_cycles;
      65             : 
      66             :     /** Absolute time as floating point number in seconds. */
      67             :     f64 time;
      68             :   };
      69             : 
      70             :   /** Event type index. */
      71             :   u16 event_type;
      72             : 
      73             :   /** Track for this event.  Tracks allow events to be sorted and
      74             :      displayed by track.  Think of 2 dimensional display with time and
      75             :      track being the x and y axes. */
      76             :   u16 track;
      77             : 
      78             :   /** 20-bytes of data follows, pads to 32 bytes. */
      79             :   u8 data[20];
      80             : } elog_event_t;
      81             : 
      82             : typedef struct
      83             : {
      84             :   /** Type index plus one assigned to this type.
      85             :      This is used to mark type as seen. */
      86             :   u32 type_index_plus_one;
      87             : 
      88             :   /** String table as a vector constructed when type is registered. */
      89             :   char **enum_strings_vector;
      90             : 
      91             :   /** Format string. (example: "my-event (%d,%d)"). */
      92             :   char *format;
      93             : 
      94             :   /** Specifies how arguments to format are parsed from event data.
      95             :      String of characters '0' '1' or '2' '3' to specify log2 size of data
      96             :      (e.g. for u8, u16, u32 or u64),
      97             :      's' means a null-terminated C string
      98             :      't' means argument is an index into enum string table for this type.
      99             :      'e' is a float,
     100             :      'f' is a double. */
     101             :   char *format_args;
     102             : 
     103             :   /** Function name generating event. */
     104             :   char *function;
     105             : 
     106             :   /** Number of elements in string enum table. */
     107             :   u32 n_enum_strings;
     108             : 
     109             :   /** String table for enum/number to string formatting. */
     110             :   char *enum_strings[];
     111             : } elog_event_type_t;
     112             : 
     113             : typedef struct
     114             : {
     115             :   /** Track name vector. */
     116             :   char *name;
     117             : 
     118             :   /** Set to one when track has been added to
     119             :      main structure. */
     120             :   u32 track_index_plus_one;
     121             : } elog_track_t;
     122             : 
     123             : typedef struct
     124             : {
     125             :   /** CPU cycle counter. */
     126             :   u64 cpu;
     127             : 
     128             :   /** OS timer in nano secs since epoch 3/30/2017, see elog_time_now() */
     129             :   u64 os_nsec;
     130             : } elog_time_stamp_t;
     131             : 
     132             : typedef struct
     133             : {
     134             :   /** Total number of events in buffer. */
     135             :   u32 n_total_events;
     136             : 
     137             :   /** When count reaches limit logging is disabled.  This is
     138             :      used for event triggers. */
     139             :   u32 n_total_events_disable_limit;
     140             : 
     141             :   /** Dummy event to use when logger is disabled. */
     142             :   elog_event_t placeholder_event;
     143             : 
     144             :   /** Power of 2 number of elements in ring. */
     145             :   uword event_ring_size;
     146             : 
     147             :   /** Vector of events (circular buffer).  Power of 2 size.
     148             :       Used when events are being collected. */
     149             :   elog_event_t *event_ring;
     150             : 
     151             :   /** Vector of event types. */
     152             :   elog_event_type_t *event_types;
     153             : 
     154             :   /** Hash table mapping type format to type index. */
     155             :   uword *event_type_by_format;
     156             : 
     157             :   /** Events may refer to strings in string table. */
     158             :   char *string_table;
     159             :   uword *string_table_hash;
     160             :   u8 *string_table_tmp;
     161             : 
     162             :   /** Vector of tracks. */
     163             :   elog_track_t *tracks;
     164             : 
     165             :   /** Default track. */
     166             :   elog_track_t default_track;
     167             : 
     168             :   /** Place holder for CPU clock frequency. */
     169             :   clib_time_t cpu_timer;
     170             : 
     171             :   /** Timestamps */
     172             :   elog_time_stamp_t init_time, serialize_time;
     173             : 
     174             :   /** SMP lock, non-zero means locking required */
     175             :   uword *lock;
     176             : 
     177             :   /** Use serialize_time and init_time to give estimate for
     178             :       cpu clock frequency. */
     179             :   f64 nsec_per_cpu_clock;
     180             : 
     181             :   /** Vector of events converted to generic form after collection. */
     182             :   elog_event_t *events;
     183             : } elog_main_t;
     184             : 
     185             : /** @brief Return number of events in the event-log buffer
     186             :     @param em elog_main_t *
     187             :     @return number of events in the buffer
     188             : */
     189             : 
     190             : always_inline uword
     191           0 : elog_n_events_in_buffer (elog_main_t * em)
     192             : {
     193           0 :   return clib_min (em->n_total_events, em->event_ring_size);
     194             : }
     195             : 
     196             : /** @brief Return number of events which can fit in the event buffer
     197             :     @param em elog_main_t *
     198             :     @return number of events which can fit in the buffer
     199             : */
     200             : always_inline uword
     201           0 : elog_buffer_capacity (elog_main_t * em)
     202             : {
     203           0 :   return em->event_ring_size;
     204             : }
     205             : 
     206             : /** @brief Reset the event buffer
     207             :     @param em elog_main_t *
     208             : */
     209             : always_inline void
     210          20 : elog_reset_buffer (elog_main_t * em)
     211             : {
     212          20 :   em->n_total_events = 0;
     213          20 :   em->n_total_events_disable_limit = ~0;
     214          20 : }
     215             : 
     216             : /** @brief Enable or disable event logging
     217             :     @param em elog_main_t *
     218             : */
     219             : always_inline void
     220         575 : elog_enable_disable (elog_main_t * em, int is_enabled)
     221             : {
     222         575 :   em->n_total_events = 0;
     223         575 :   em->n_total_events_disable_limit = is_enabled ? ~0 : 0;
     224         575 : }
     225             : 
     226             : /** @brief disable logging after specified number of ievents have been logged.
     227             : 
     228             :    This is used as a "debug trigger" when a certain event has occurred.
     229             :    Events will be logged both before and after the "event" but the
     230             :    event will not be lost as long as N < RING_SIZE.
     231             : 
     232             :    @param em elog_main_t *
     233             :    @param n uword number of events before disabling event logging
     234             : */
     235             : always_inline void
     236             : elog_disable_after_events (elog_main_t * em, uword n)
     237             : {
     238             :   em->n_total_events_disable_limit = em->n_total_events + n;
     239             : }
     240             : 
     241             : /* @brief mid-buffer logic-analyzer trigger
     242             : 
     243             :    Currently, only midpoint triggering is supported, but it's pretty obvious
     244             :    how to generalize the scheme.
     245             :    @param em elog_main_t *
     246             : */
     247             : always_inline void
     248             : elog_disable_trigger (elog_main_t * em)
     249             : {
     250             :   em->n_total_events_disable_limit =
     251             :     em->n_total_events + vec_len (em->event_ring) / 2;
     252             : }
     253             : 
     254             : /** @brief register an event type
     255             :     @param em elog_main_t *
     256             :     @param t elog_event_type_t * event to register
     257             :     @return type index
     258             :     @warning Typically not called directly
     259             : */
     260             : 
     261             : word elog_event_type_register (elog_main_t * em, elog_event_type_t * t);
     262             : 
     263             : /** @brief register an event track
     264             :     @param em elog_main_t *
     265             :     @param t elog_track_t * track to register
     266             :     @return track index
     267             :     @note this function is often called directly
     268             : */
     269             : word elog_track_register (elog_main_t * em, elog_track_t * t);
     270             : 
     271             : /** @brief event logging enabled predicate
     272             :     @param em elog_main_t *
     273             :     @return 1 if enabled, 0 if not enabled
     274             : */
     275             : always_inline uword
     276     2021117 : elog_is_enabled (elog_main_t * em)
     277             : {
     278     2021117 :   return em->n_total_events < em->n_total_events_disable_limit;
     279             : }
     280             : 
     281             : /** @brief Allocate an event to be filled in by the caller
     282             : 
     283             :     Not normally called directly; this function underlies the
     284             :     ELOG_DATA and ELOG_TRACK_DATA macros
     285             : 
     286             :     @param em elog_main_t *
     287             :     @param type elog_event_type_t * type
     288             :     @param track elog_track_t * track
     289             :     @param cpu_time u64 current cpu tick value
     290             :     @returns event to be filled in
     291             : */
     292             : always_inline void *
     293     1010560 : elog_event_data_inline (elog_main_t * em,
     294             :                         elog_event_type_t * type,
     295             :                         elog_track_t * track, u64 cpu_time)
     296             : {
     297             :   elog_event_t *e;
     298             :   uword ei;
     299             :   word type_index, track_index;
     300             : 
     301             :   /* Return the user placeholder memory to scribble data into. */
     302     1010560 :   if (PREDICT_FALSE (!elog_is_enabled (em)))
     303           0 :     return em->placeholder_event.data;
     304             : 
     305     1010560 :   type_index = (word) type->type_index_plus_one - 1;
     306     1010560 :   track_index = (word) track->track_index_plus_one - 1;
     307     1010560 :   if (PREDICT_FALSE ((type_index | track_index) < 0))
     308             :     {
     309        2454 :       if (type_index < 0)
     310        2454 :         type_index = elog_event_type_register (em, type);
     311        2454 :       if (track_index < 0)
     312           0 :         track_index = elog_track_register (em, track);
     313             :     }
     314             : 
     315     1010560 :   ASSERT (track_index < vec_len (em->tracks));
     316     1010560 :   ASSERT (is_pow2 (vec_len (em->event_ring)));
     317             : 
     318     1010560 :   if (em->lock)
     319     1010560 :     ei = clib_atomic_fetch_add (&em->n_total_events, 1);
     320             :   else
     321           0 :     ei = em->n_total_events++;
     322             : 
     323     1010560 :   ei &= em->event_ring_size - 1;
     324     1010560 :   e = vec_elt_at_index (em->event_ring, ei);
     325             : 
     326     1010560 :   e->time_cycles = cpu_time;
     327     1010560 :   e->event_type = type_index;
     328     1010560 :   e->track = track_index;
     329             : 
     330             :   /* Return user data for caller to fill in. */
     331     1010560 :   return e->data;
     332             : }
     333             : 
     334             : /* External version of inline. */
     335             : void *elog_event_data (elog_main_t * em,
     336             :                        elog_event_type_t * type,
     337             :                        elog_track_t * track, u64 cpu_time);
     338             : 
     339             : /** @brief Allocate an event to be filled in by the caller, non-inline
     340             : 
     341             :     Not normally called directly; this function underlies the
     342             :     ELOG_DATA and ELOG_TRACK_DATA macros
     343             : 
     344             :     @param em elog_main_t *
     345             :     @param type elog_event_type_t * type
     346             :     @param track elog_track_t * track
     347             :     @param cpu_time u64 current cpu tick value
     348             :     @returns event to be filled in
     349             : */
     350             : always_inline void *
     351     1010557 : elog_event_data_not_inline (elog_main_t * em,
     352             :                             elog_event_type_t * type,
     353             :                             elog_track_t * track, u64 cpu_time)
     354             : {
     355             :   /* Return the user placeholder memory to scribble data into. */
     356     1010557 :   if (PREDICT_FALSE (!elog_is_enabled (em)))
     357           0 :     return em->placeholder_event.data;
     358     1010557 :   return elog_event_data (em, type, track, cpu_time);
     359             : }
     360             : 
     361             : /** @brief Log a single-datum event
     362             :     @param em elog_main_t *
     363             :     @param type elog_event_type_t * type
     364             :     @param data u32 single datum to capture
     365             : */
     366             : always_inline void
     367           0 : elog (elog_main_t * em, elog_event_type_t * type, u32 data)
     368             : {
     369           0 :   u32 *d = elog_event_data_not_inline (em,
     370             :                                        type,
     371             :                                        &em->default_track,
     372             :                                        clib_cpu_time_now ());
     373           0 :   d[0] = data;
     374           0 : }
     375             : 
     376             : /** @brief Log a single-datum event, inline version
     377             :     @param em elog_main_t *
     378             :     @param type elog_event_type_t * type
     379             :     @param data u32 single datum to capture
     380             : */
     381             : always_inline void
     382             : elog_inline (elog_main_t * em, elog_event_type_t * type, u32 data)
     383             : {
     384             :   u32 *d = elog_event_data_inline (em,
     385             :                                    type,
     386             :                                    &em->default_track,
     387             :                                    clib_cpu_time_now ());
     388             :   d[0] = data;
     389             : }
     390             : 
     391             : /** @brief Log a single-datum event to a specific track, non-inline version
     392             :     @param em elog_main_t *
     393             :     @param type elog_event_type_t * type
     394             :     @param type elog_event_track_t * track
     395             :     @param data u32 single datum to capture
     396             : */
     397             : always_inline void
     398           0 : elog_track (elog_main_t * em, elog_event_type_t * type, elog_track_t * track,
     399             :             u32 data)
     400             : {
     401           0 :   u32 *d = elog_event_data_not_inline (em,
     402             :                                        type,
     403             :                                        track,
     404             :                                        clib_cpu_time_now ());
     405           0 :   d[0] = data;
     406           0 : }
     407             : 
     408             : /** @brief Log a single-datum event to a specific track
     409             :     @param em elog_main_t *
     410             :     @param type elog_event_type_t * type
     411             :     @param type elog_event_track_t * track
     412             :     @param data u32 single datum to capture
     413             : */
     414             : always_inline void
     415             : elog_track_inline (elog_main_t * em, elog_event_type_t * type,
     416             :                    elog_track_t * track, u32 data)
     417             : {
     418             :   u32 *d = elog_event_data_inline (em,
     419             :                                    type,
     420             :                                    track,
     421             :                                    clib_cpu_time_now ());
     422             :   d[0] = data;
     423             : }
     424             : 
     425             : always_inline void *
     426     1010557 : elog_data (elog_main_t * em, elog_event_type_t * type, elog_track_t * track)
     427             : {
     428     1010557 :   return elog_event_data_not_inline (em, type, track, clib_cpu_time_now ());
     429             : }
     430             : 
     431             : always_inline void *
     432             : elog_data_inline (elog_main_t * em, elog_event_type_t * type,
     433             :                   elog_track_t * track)
     434             : {
     435             :   return elog_event_data_inline (em, type, track, clib_cpu_time_now ());
     436             : }
     437             : 
     438             : /* Macro shorthands for generating/declaring events. */
     439             : #define __ELOG_TYPE_VAR(f) f
     440             : #define __ELOG_TRACK_VAR(f) f
     441             : 
     442             : #define ELOG_TYPE_DECLARE(f) static elog_event_type_t __ELOG_TYPE_VAR(f)
     443             : 
     444             : #define ELOG_TYPE_INIT_FORMAT_AND_FUNCTION(fmt,func) \
     445             :   { .format = fmt, .function = func, }
     446             : 
     447             : #define ELOG_TYPE_INIT(fmt) \
     448             :   ELOG_TYPE_INIT_FORMAT_AND_FUNCTION(fmt,(char *) __FUNCTION__)
     449             : 
     450             : #define ELOG_TYPE_DECLARE_HELPER(f,fmt,func)            \
     451             :   static elog_event_type_t __ELOG_TYPE_VAR(f) =         \
     452             :     ELOG_TYPE_INIT_FORMAT_AND_FUNCTION (fmt, func)
     453             : 
     454             : #define ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION(f,fmt)            \
     455             :   ELOG_TYPE_DECLARE_HELPER (f, fmt, (char *) __FUNCTION__)
     456             : 
     457             : #define ELOG_TYPE_DECLARE_FORMAT(f,fmt)         \
     458             :   ELOG_TYPE_DECLARE_HELPER (f, fmt, 0)
     459             : 
     460             : /* Shorthands with and without __FUNCTION__.
     461             :    D for decimal; X for hex.  F for __FUNCTION__. */
     462             : #define ELOG_TYPE(f,fmt) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION(f,fmt)
     463             : #define ELOG_TYPE_D(f)  ELOG_TYPE_DECLARE_FORMAT (f, #f " %d")
     464             : #define ELOG_TYPE_X(f)  ELOG_TYPE_DECLARE_FORMAT (f, #f " 0x%x")
     465             : #define ELOG_TYPE_DF(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " %d")
     466             : #define ELOG_TYPE_XF(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " 0x%x")
     467             : #define ELOG_TYPE_FD(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " %d")
     468             : #define ELOG_TYPE_FX(f) ELOG_TYPE_DECLARE_FORMAT_AND_FUNCTION (f, #f " 0x%x")
     469             : 
     470             : #define ELOG_TRACK_DECLARE(f) static elog_track_t __ELOG_TRACK_VAR(f)
     471             : #define ELOG_TRACK(f) ELOG_TRACK_DECLARE(f) = { .name = #f, }
     472             : 
     473             : /* Log 32 bits of data. */
     474             : #define ELOG(em,f,data) elog ((em), &__ELOG_TYPE_VAR(f), data)
     475             : #define ELOG_INLINE(em,f,data) elog_inline ((em), &__ELOG_TYPE_VAR(f), data)
     476             : 
     477             : /* Return data pointer to fill in. */
     478             : #define ELOG_TRACK_DATA(em,f,track) \
     479             :   elog_data ((em), &__ELOG_TYPE_VAR(f), &__ELOG_TRACK_VAR(track))
     480             : #define ELOG_TRACK_DATA_INLINE(em,f,track) \
     481             :   elog_data_inline ((em), &__ELOG_TYPE_VAR(f), &__ELOG_TRACK_VAR(track))
     482             : 
     483             : /* Shorthand with default track. */
     484             : #define ELOG_DATA(em,f) elog_data ((em), &__ELOG_TYPE_VAR (f), &(em)->default_track)
     485             : #define ELOG_DATA_INLINE(em,f) elog_data_inline ((em), &__ELOG_TYPE_VAR (f), &(em)->default_track)
     486             : 
     487             : /** @brief add a string to the event-log string table
     488             : 
     489             :     Often combined with hashing and the T4 elog format specifier to
     490             :     display complex strings in offline tooling
     491             : 
     492             :     @param em elog_main_t *
     493             :     @param format char *
     494             :     @param VARARGS
     495             :     @return u32 index to add to event log
     496             : */
     497             : u32 elog_string (elog_main_t * em, char *format, ...);
     498             : 
     499             : void elog_time_now (elog_time_stamp_t * et);
     500             : 
     501             : /** @brief convert event ring events to events, and return them as a vector.
     502             :     @param em elog_main_t *
     503             :     @return event vector with timestamps in f64 seconds
     504             :     @note sets em->events to resulting vector.
     505             : */
     506             : elog_event_t *elog_get_events (elog_main_t * em);
     507             : 
     508             : /** @brief convert event ring events to events, and return them as a vector.
     509             :     @param em elog_main_t *
     510             :     @return event vector with timestamps in f64 seconds
     511             :     @note no side effects
     512             : */
     513             : elog_event_t *elog_peek_events (elog_main_t * em);
     514             : 
     515             : /* Merge two logs, add supplied track tags. */
     516             : void elog_merge (elog_main_t * dst, u8 * dst_tag,
     517             :                  elog_main_t * src, u8 * src_tag, f64 align_tweak);
     518             : 
     519             : /* 2 arguments elog_main_t and elog_event_t to format event or track name. */
     520             : u8 *format_elog_event (u8 * s, va_list * va);
     521             : u8 *format_elog_track_name (u8 * s, va_list * va);
     522             : u8 *format_elog_track (u8 * s, va_list * args);
     523             : 
     524             : void serialize_elog_main (serialize_main_t * m, va_list * va);
     525             : void unserialize_elog_main (serialize_main_t * m, va_list * va);
     526             : 
     527             : void elog_init (elog_main_t * em, u32 n_events);
     528             : void elog_alloc (elog_main_t * em, u32 n_events);
     529             : void elog_resize (elog_main_t * em, u32 n_events);
     530             : 
     531             : #ifdef CLIB_UNIX
     532             : always_inline clib_error_t *
     533           0 : elog_write_file (elog_main_t * em, char *clib_file, int flush_ring)
     534             : {
     535             :   serialize_main_t m;
     536             :   clib_error_t *error;
     537             : 
     538           0 :   error = serialize_open_clib_file (&m, clib_file);
     539           0 :   if (error)
     540           0 :     return error;
     541           0 :   error = serialize (&m, serialize_elog_main, em, flush_ring);
     542           0 :   if (!error)
     543           0 :     serialize_close (&m);
     544           0 :   return error;
     545             : }
     546             : 
     547             : clib_error_t *elog_write_file_not_inline (elog_main_t * em, char *clib_file,
     548             :                                           int flush_ring);
     549             : 
     550             : always_inline clib_error_t *
     551             : elog_read_file (elog_main_t * em, char *clib_file)
     552             : {
     553             :   serialize_main_t m;
     554             :   clib_error_t *error;
     555             : 
     556             :   error = unserialize_open_clib_file (&m, clib_file);
     557             :   if (error)
     558             :     return error;
     559             :   error = unserialize (&m, unserialize_elog_main, em);
     560             :   if (!error)
     561             :     unserialize_close (&m);
     562             :   return error;
     563             : }
     564             : 
     565             : clib_error_t *elog_read_file_not_inline (elog_main_t * em, char *clib_file);
     566             : char *format_one_elog_event (void *em_arg, void *ep_arg);
     567             : 
     568             : #endif /* CLIB_UNIX */
     569             : 
     570             : #endif /* included_clib_elog_h */
     571             : 
     572             : /*
     573             :  * fd.io coding-style-patch-verification: ON
     574             :  *
     575             :  * Local Variables:
     576             :  * eval: (c-set-style "gnu")
     577             :  * End:
     578             :  */

Generated by: LCOV version 1.14