X86_64 perf counter plugin

Change-Id: Ie5a00c15ee9536cc61afab57f6cadc1aa1972f3c
Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
Dave Barach
2018-09-10 12:31:15 -04:00
committed by Damjan Marion
parent 115a3ac59a
commit 4d1a866aff
13 changed files with 1632 additions and 26 deletions

View File

@ -28,6 +28,11 @@ do
fi
done
# Perf monitor .json files
for i in $(find ${1}/vpp/share/vpp/plugins/perfmon -name *.json -type f -print); do
echo ../${i} /usr/share/vpp/plugins/perfmon >> ${2}
done
# sample plugin
paths=`(cd ..; find src/examples/sample-plugin -type f -print | grep -v autom4te)`

View File

@ -0,0 +1,38 @@
# Copyright (c) 2018 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.
add_vpp_plugin(perfmon
SOURCES
perfmon.c
perfmon_periodic.c
parse_util.c
)
# Reenable / extend when .json file license issue fixed
#
# set (PERFMON_JSON_FILES
# haswell_core_v28.json
# haswellx_core_v20.json
# ivybridge_core_v21.json
# ivytown_core_v20.json
# jaketown_core_v20.json
# sandybridge_core_v16.json
# skylake_core_v42.json
# skylakex_core_v1.12.json
# )
# install(
# FILES ${PERFMON_JSON_FILES}
# DESTINATION share/vpp/plugins/perfmon
# COMPONENT vpp-dev
# )

View File

@ -0,0 +1,235 @@
/*
* parse_util.c - halfhearted json parser
*
* Copyright (c) 2018 Cisco Systems 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.
*/
#include <perfmon/perfmon.h>
#include <vppinfra/unix.h>
typedef enum
{
STATE_START,
STATE_READ_NAME,
STATE_READ_VALUE,
} parse_state_t;
static u8 *
downcase (u8 * s)
{
u8 *rv = 0;
u8 c;
int i;
for (i = 0; i < vec_len (s); i++)
{
c = s[i];
if (c >= 'A' && c <= 'Z')
c = c + ('a' - 'A');
vec_add1 (rv, c);
}
return (rv);
}
uword *
perfmon_parse_table (perfmon_main_t * pm, char *path, char *table_name)
{
u8 *cp;
u8 *event_name;
int state = STATE_START;
uword *ht;
name_value_pair_t *nvp = 0;
name_value_pair_t **nvps = 0;
u8 *v;
int i;
u8 *json_filename;
clib_error_t *error;
/* Create the name/value hash table in any case... */
ht = hash_create_string (0, sizeof (uword));
json_filename = format (0, "%s/%s%c", path, table_name, 0);
vlib_log_debug (pm->log_class, "Try to read perfmon events from %s",
json_filename);
error = unix_proc_file_contents ((char *) json_filename, &cp);
if (error)
{
vlib_log_err (pm->log_class,
"Failed to read CPU-specific counter table");
vlib_log_err (pm->log_class,
"Download from https://download.01.org/perfmon, "
"and install as %s", json_filename);
vec_free (json_filename);
clib_error_report (error);
return ht;
}
vlib_log_debug (pm->log_class, "Read OK, parse the event table...");
vec_free (json_filename);
again:
while (*cp)
{
switch (state)
{
case STATE_START:
while (*cp && *cp != '{' && *cp != '}' && *cp != ',')
cp++;
if (*cp == 0)
goto done;
/* Look for a new event */
if (*cp == '{')
{
if (*cp == 0)
{
error:
clib_warning ("parse fail");
hash_free (ht);
return 0;
}
cp++;
state = STATE_READ_NAME;
goto again;
}
else if (*cp == '}') /* end of event */
{
/* Look for the "EventName" nvp */
for (i = 0; i < vec_len (nvps); i++)
{
nvp = nvps[i];
if (!strncmp ((char *) nvp->name, "EventName", 9))
{
event_name = nvp->value;
goto found;
}
}
/* no name? */
for (i = 0; i < vec_len (nvps); i++)
{
vec_free (nvps[i]->name);
vec_free (nvps[i]->value);
}
vec_free (nvps);
cp++;
goto again;
found:
event_name = downcase (event_name);
hash_set_mem (ht, event_name, nvps);
nvp = 0;
nvps = 0;
cp++;
goto again;
}
else if (*cp == ',') /* punctuation */
{
cp++;
goto again;
}
case STATE_READ_NAME:
vec_validate (nvp, 0);
v = 0;
while (*cp && *cp != '"')
cp++;
if (*cp == 0)
{
vec_free (nvp);
goto error;
}
cp++;
while (*cp && *cp != '"')
{
vec_add1 (v, *cp);
cp++;
}
if (*cp == 0)
{
vec_free (v);
goto error;
}
cp++;
vec_add1 (v, 0);
nvp->name = v;
state = STATE_READ_VALUE;
goto again;
case STATE_READ_VALUE:
while (*cp && *cp != ':')
cp++;
if (*cp == 0)
{
vec_free (nvp->name);
goto error;
}
while (*cp && *cp != '"')
cp++;
if (*cp == 0)
{
vec_free (nvp->name);
goto error;
}
else
cp++;
v = 0;
while (*cp && *cp != '"')
{
vec_add1 (v, *cp);
cp++;
}
if (*cp == 0)
{
vec_free (nvp->name);
vec_free (v);
goto error;
}
vec_add1 (v, 0);
nvp->value = v;
vec_add1 (nvps, nvp);
while (*cp && *cp != ',' && *cp != '}')
cp++;
if (*cp == 0)
{
vec_free (nvp->name);
vec_free (nvp->value);
goto error;
}
else if (*cp == '}')
state = STATE_START;
else
{
cp++;
state = STATE_READ_NAME;
}
nvp = 0;
goto again;
}
}
done:
return (ht);
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
/*
* perfmon.h - performance monitor
*
* Copyright (c) 2018 Cisco Systems 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.
*/
#ifndef __included_perfmon_h__
#define __included_perfmon_h__
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vnet/ethernet/ethernet.h>
#include <vlib/log.h>
#include <vppinfra/hash.h>
#include <vppinfra/error.h>
#include <linux/perf_event.h>
#define foreach_perfmon_event \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES, "cpu-cycles") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS, "instructions") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES, \
"cache-references") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES, "cache-misses") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branches") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES, "bus-cycles") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, \
"stall-frontend") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND, \
"stall-backend") \
_(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES, "ref-cpu-cycles") \
_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS, "page-faults") \
_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES, "context-switches") \
_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS, "cpu-migrations") \
_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN, "minor-pagefaults") \
_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ, "major-pagefaults") \
_(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS, "emulation-faults")
typedef struct
{
char *name;
int pe_type;
int pe_config;
} perfmon_event_config_t;
typedef enum
{
PERFMON_STATE_OFF = 0,
PERFMON_STATE_RUNNING,
} perfmon_state_t;
typedef struct
{
u8 *thread_and_node_name;
u8 **counter_names;
u64 *counter_values;
u64 *vectors_this_counter;
} perfmon_capture_t;
typedef struct
{
u32 cpuid;
const char **table;
} perfmon_cpuid_and_table_t;
typedef struct
{
u8 *name;
u8 *value;
} name_value_pair_t;
typedef struct
{
/* API message ID base */
u16 msg_id_base;
/* on/off switch for the periodic function */
volatile u8 state;
/* capture pool, hash table */
perfmon_capture_t *capture_pool;
uword *capture_by_thread_and_node_name;
/* CPU-specific event tables, hash table of selected table (if any) */
perfmon_cpuid_and_table_t *perfmon_tables;
uword *perfmon_table;
/* vector of events to collect */
perfmon_event_config_t *events_to_collect;
/* Base indices of synthetic event tuples */
u32 ipc_event_index;
u32 mispredict_event_index;
/* Length of time to capture a single event */
f64 timeout_interval;
/* Current event (index) being collected */
u32 current_event;
u32 *rdpmc_indices;
/* mmap base / size of (mapped) struct perf_event_mmap_page */
u8 **perf_event_pages;
u32 page_size;
/* Current perf_event file descriptors, per thread */
int *pm_fds;
/* Logging */
vlib_log_class_t log_class;
/* convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
ethernet_main_t *ethernet_main;
} perfmon_main_t;
extern perfmon_main_t perfmon_main;
extern vlib_node_registration_t perfmon_periodic_node;
uword *perfmon_parse_table (perfmon_main_t * pm, char *path, char *filename);
/* Periodic function events */
#define PERFMON_START 1
#endif /* __included_perfmon_h__ */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@ -540,29 +540,38 @@ vlib_put_next_frame (vlib_main_t * vm,
never_inline void
vlib_node_runtime_sync_stats (vlib_main_t * vm,
vlib_node_runtime_t * r,
uword n_calls, uword n_vectors, uword n_clocks)
uword n_calls, uword n_vectors, uword n_clocks,
uword n_ticks)
{
vlib_node_t *n = vlib_get_node (vm, r->node_index);
n->stats_total.calls += n_calls + r->calls_since_last_overflow;
n->stats_total.vectors += n_vectors + r->vectors_since_last_overflow;
n->stats_total.clocks += n_clocks + r->clocks_since_last_overflow;
n->stats_total.perf_counter_ticks += n_ticks +
r->perf_counter_ticks_since_last_overflow;
n->stats_total.perf_counter_vectors += n_vectors +
r->perf_counter_vectors_since_last_overflow;
n->stats_total.max_clock = r->max_clock;
n->stats_total.max_clock_n = r->max_clock_n;
r->calls_since_last_overflow = 0;
r->vectors_since_last_overflow = 0;
r->clocks_since_last_overflow = 0;
r->perf_counter_ticks_since_last_overflow = 0ULL;
r->perf_counter_vectors_since_last_overflow = 0ULL;
}
always_inline void __attribute__ ((unused))
vlib_process_sync_stats (vlib_main_t * vm,
vlib_process_t * p,
uword n_calls, uword n_vectors, uword n_clocks)
uword n_calls, uword n_vectors, uword n_clocks,
uword n_ticks)
{
vlib_node_runtime_t *rt = &p->node_runtime;
vlib_node_t *n = vlib_get_node (vm, rt->node_index);
vlib_node_runtime_sync_stats (vm, rt, n_calls, n_vectors, n_clocks);
vlib_node_runtime_sync_stats (vm, rt, n_calls, n_vectors, n_clocks,
n_ticks);
n->stats_total.suspends += p->n_suspends;
p->n_suspends = 0;
}
@ -588,7 +597,7 @@ vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n)
vec_elt_at_index (vm->node_main.nodes_by_type[n->type],
n->runtime_index);
vlib_node_runtime_sync_stats (vm, rt, 0, 0, 0);
vlib_node_runtime_sync_stats (vm, rt, 0, 0, 0, 0);
/* Sync up runtime next frame vector counters with main node structure. */
{
@ -608,45 +617,68 @@ always_inline u32
vlib_node_runtime_update_stats (vlib_main_t * vm,
vlib_node_runtime_t * node,
uword n_calls,
uword n_vectors, uword n_clocks)
uword n_vectors, uword n_clocks,
uword n_ticks)
{
u32 ca0, ca1, v0, v1, cl0, cl1, r;
u32 ptick0, ptick1, pvec0, pvec1;
cl0 = cl1 = node->clocks_since_last_overflow;
ca0 = ca1 = node->calls_since_last_overflow;
v0 = v1 = node->vectors_since_last_overflow;
ptick0 = ptick1 = node->perf_counter_ticks_since_last_overflow;
pvec0 = pvec1 = node->perf_counter_vectors_since_last_overflow;
ca1 = ca0 + n_calls;
v1 = v0 + n_vectors;
cl1 = cl0 + n_clocks;
ptick1 = ptick0 + n_ticks;
pvec1 = pvec0 + n_vectors;
node->calls_since_last_overflow = ca1;
node->clocks_since_last_overflow = cl1;
node->vectors_since_last_overflow = v1;
node->perf_counter_ticks_since_last_overflow = ptick1;
node->perf_counter_vectors_since_last_overflow = pvec1;
node->max_clock_n = node->max_clock > n_clocks ?
node->max_clock_n : n_vectors;
node->max_clock = node->max_clock > n_clocks ? node->max_clock : n_clocks;
r = vlib_node_runtime_update_main_loop_vector_stats (vm, node, n_vectors);
if (PREDICT_FALSE (ca1 < ca0 || v1 < v0 || cl1 < cl0))
if (PREDICT_FALSE (ca1 < ca0 || v1 < v0 || cl1 < cl0) || (ptick1 < ptick0)
|| (pvec1 < pvec0))
{
node->calls_since_last_overflow = ca0;
node->clocks_since_last_overflow = cl0;
node->vectors_since_last_overflow = v0;
vlib_node_runtime_sync_stats (vm, node, n_calls, n_vectors, n_clocks);
node->perf_counter_ticks_since_last_overflow = ptick0;
node->perf_counter_vectors_since_last_overflow = pvec0;
vlib_node_runtime_sync_stats (vm, node, n_calls, n_vectors, n_clocks,
n_ticks);
}
return r;
}
static inline u64
vlib_node_runtime_perf_counter (vlib_main_t * vm)
{
if (PREDICT_FALSE (vm->vlib_node_runtime_perf_counter_cb != 0))
return ((*vm->vlib_node_runtime_perf_counter_cb) (vm));
return 0ULL;
}
always_inline void
vlib_process_update_stats (vlib_main_t * vm,
vlib_process_t * p,
uword n_calls, uword n_vectors, uword n_clocks)
uword n_calls, uword n_vectors, uword n_clocks,
uword n_ticks)
{
vlib_node_runtime_update_stats (vm, &p->node_runtime,
n_calls, n_vectors, n_clocks);
n_calls, n_vectors, n_clocks, n_ticks);
}
static clib_error_t *
@ -959,15 +991,19 @@ dispatch_node (vlib_main_t * vm,
if (1 /* || vm->thread_index == node->thread_index */ )
{
vlib_main_t *stat_vm;
stat_vm = /* vlib_mains ? vlib_mains[0] : */ vm;
u64 pmc_before, pmc_delta;
vlib_elog_main_loop_event (vm, node->node_index,
last_time_stamp,
frame ? frame->n_vectors : 0,
/* is_after */ 0);
/*
* To validate accounting: pmc_before = last_time_stamp
* perf ticks should equal clocks/pkt...
*/
pmc_before = vlib_node_runtime_perf_counter (vm);
/*
* Turn this on if you run into
* "bad monkey" contexts, and you want to know exactly
@ -990,16 +1026,23 @@ dispatch_node (vlib_main_t * vm,
t = clib_cpu_time_now ();
/*
* To validate accounting: pmc_delta = t - pmc_before;
* perf ticks should equal clocks/pkt...
*/
pmc_delta = vlib_node_runtime_perf_counter (vm) - pmc_before;
vlib_elog_main_loop_event (vm, node->node_index, t, n, /* is_after */
1);
vm->main_loop_vectors_processed += n;
vm->main_loop_nodes_processed += n > 0;
v = vlib_node_runtime_update_stats (stat_vm, node,
v = vlib_node_runtime_update_stats (vm, node,
/* n_calls */ 1,
/* n_vectors */ n,
/* n_clocks */ t - last_time_stamp);
/* n_clocks */ t - last_time_stamp,
pmc_delta /* PMC ticks */ );
/* When in interrupt mode and vector rate crosses threshold switch to
polling mode. */
@ -1338,7 +1381,8 @@ dispatch_process (vlib_main_t * vm,
vlib_process_update_stats (vm, p,
/* n_calls */ !is_suspend,
/* n_vectors */ n_vectors,
/* n_clocks */ t - last_time_stamp);
/* n_clocks */ t - last_time_stamp,
/* pmc_ticks */ 0ULL);
return t;
}
@ -1421,7 +1465,8 @@ dispatch_suspended_process (vlib_main_t * vm,
vlib_process_update_stats (vm, p,
/* n_calls */ !is_suspend,
/* n_vectors */ n_vectors,
/* n_clocks */ t - last_time_stamp);
/* n_clocks */ t - last_time_stamp,
/* pmc_ticks */ 0ULL);
return t;
}
@ -1471,6 +1516,9 @@ vlib_main_or_worker_loop (vlib_main_t * vm, int is_main)
if (!nm->interrupt_threshold_vector_length)
nm->interrupt_threshold_vector_length = 5;
/* Make sure the performance monitor counter is disabled */
vm->perf_counter_id = ~0;
/* Start all processes. */
if (is_main)
{
@ -1493,6 +1541,9 @@ vlib_main_or_worker_loop (vlib_main_t * vm, int is_main)
vlib_worker_thread_barrier_check ();
vec_foreach (fqm, tm->frame_queue_mains)
vlib_frame_queue_dequeue (vm, fqm);
if (PREDICT_FALSE (vm->worker_thread_main_loop_callback != 0))
((void (*)(vlib_main_t *)) vm->worker_thread_main_loop_callback)
(vm);
}
/* Process pre-input nodes. */

View File

@ -46,6 +46,7 @@
#include <vppinfra/pool.h>
#include <vppinfra/random_buffer.h>
#include <vppinfra/time.h>
#include <vppinfra/pmc.h>
#include <pthread.h>
@ -81,6 +82,11 @@ typedef struct vlib_main_t
u32 vector_counts_per_main_loop[2];
u32 node_counts_per_main_loop[2];
/* Main loop hw / sw performance counters */
u64 (*vlib_node_runtime_perf_counter_cb) (struct vlib_main_t *);
int perf_counter_id;
int perf_counter_fd;
/* Every so often we switch to the next counter. */
#define VLIB_LOG2_MAIN_LOOPS_PER_STATS_UPDATE 7
@ -192,6 +198,9 @@ typedef struct vlib_main_t
void (*queue_signal_callback) (struct vlib_main_t *);
u8 **argv;
/* Top of (worker) dispatch loop callback */
volatile void (*worker_thread_main_loop_callback) (struct vlib_main_t *);
/* debugging */
volatile int parked_at_barrier;

View File

@ -244,6 +244,8 @@ typedef struct
u64 calls, vectors, clocks, suspends;
u64 max_clock;
u64 max_clock_n;
u64 perf_counter_ticks;
u64 perf_counter_vectors;
} vlib_node_stats_t;
#define foreach_vlib_node_state \
@ -488,6 +490,9 @@ typedef struct vlib_node_runtime_t
u32 vectors_since_last_overflow; /**< Number of vector elements
processed by this node. */
u32 perf_counter_ticks_since_last_overflow; /**< Perf counter ticks */
u32 perf_counter_vectors_since_last_overflow; /**< Perf counter vectors */
u32 next_frame_index; /**< Start of next frames for this
node. */

View File

@ -148,19 +148,25 @@ format_vlib_node_stats (u8 * s, va_list * va)
f64 maxc, maxcn;
u32 maxn;
u32 indent;
u64 pmc_ticks;
f64 pmc_ticks_per_packet;
if (!n)
{
if (max)
return format (s,
"%=30s%=17s%=16s%=16s%=16s%=16s",
"Name", "Max Node Clocks", "Vectors at Max",
"Max Clocks", "Avg Clocks", "Avg Vectors/Call");
s = format (s,
"%=30s%=17s%=16s%=16s%=16s%=16s",
"Name", "Max Node Clocks", "Vectors at Max",
"Max Clocks", "Avg Clocks", "Avg Vectors/Call");
else
return format (s,
"%=30s%=12s%=16s%=16s%=16s%=16s%=16s",
"Name", "State", "Calls", "Vectors", "Suspends",
"Clocks", "Vectors/Call");
s = format (s,
"%=30s%=12s%=16s%=16s%=16s%=16s%=16s",
"Name", "State", "Calls", "Vectors", "Suspends",
"Clocks", "Vectors/Call");
if (vm->perf_counter_id)
s = format (s, "%=16s", "Perf Ticks");
return s;
}
indent = format_get_indent (s);
@ -176,6 +182,13 @@ format_vlib_node_stats (u8 * s, va_list * va)
else
maxcn = 0.0;
pmc_ticks = n->stats_total.perf_counter_ticks -
n->stats_last_clear.perf_counter_ticks;
if (p > 0)
pmc_ticks_per_packet = (f64) pmc_ticks / (f64) p;
else
pmc_ticks_per_packet = 0.0;
/* Clocks per packet, per call or per suspend. */
x = 0;
if (p > 0)
@ -208,6 +221,9 @@ format_vlib_node_stats (u8 * s, va_list * va)
s = format (s, "%-30v%=12U%16Ld%16Ld%16Ld%16.2e%16.2f", ns,
format_vlib_node_state, vm, n, c, p, d, x, v);
if (pmc_ticks_per_packet > 0.0)
s = format (s, "%16.2e", pmc_ticks_per_packet);
if (ns != n->name)
vec_free (ns);

View File

@ -57,7 +57,7 @@ vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector,
u8 *namep;
u32 name_bytes;
uword i, j, k;
u64 l, v, c, d;
u64 l, v, c, d, pmc;
state_string_enum_t state_code;
serialize_open_vector (sm, vector);
@ -77,6 +77,8 @@ vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector,
v = n->stats_total.vectors - n->stats_last_clear.vectors;
c = n->stats_total.calls - n->stats_last_clear.calls;
d = n->stats_total.suspends - n->stats_last_clear.suspends;
pmc = n->stats_total.perf_counter_ticks
- n->stats_last_clear.perf_counter_ticks;
state_code = STATE_INTERNAL;
@ -149,6 +151,8 @@ vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector,
serialize_integer (sm, v, 8);
/* Total suspends */
serialize_integer (sm, d, 8);
/* PMC counter */
serialize_integer (sm, pmc, 8);
}
else /* no stats */
serialize_likely_small_unsigned_integer (sm, 0);
@ -167,7 +171,7 @@ vlib_node_unserialize (u8 * vector)
vlib_node_t **nodes;
vlib_node_t ***nodes_by_thread = 0;
int i, j, k;
u64 l, v, c, d;
u64 l, v, c, d, pmc;
state_string_enum_t state_code;
int stats_present;
@ -225,6 +229,9 @@ vlib_node_unserialize (u8 * vector)
/* Total suspends */
unserialize_integer (sm, &d, 8);
node->stats_total.suspends = d;
/* PMC counter */
unserialize_integer (sm, &pmc, 8);
node->stats_total.perf_counter_ticks = pmc;
}
}
}

View File

@ -136,6 +136,7 @@ set(VPPINFRA_HEADERS
os.h
pipeline.h
pool.h
pmc.h
ptclosure.h
random_buffer.h
random.h

46
src/vppinfra/pmc.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2018 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.
*/
#ifndef included_clib_pmc_h
#define included_clib_pmc_h
#if defined (__x86_64__)
always_inline u64
clib_rdpmc (int counter_id)
{
u32 a, d;
asm volatile ("rdpmc":"=a" (a), "=d" (d):"c" (counter_id));
return (u64) a + ((u64) d << (u64) 32);
}
#else
always_inline u64
clib_rdpmc (int counter_id)
{
return 0ULL;
}
#endif /* __aarch64__ */
#endif /* included_clib_pmc_h */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/