summaryrefslogtreecommitdiffstats
path: root/VNFs/DPPD-PROX/stats_task.h
blob: 362b718cf7786cc188063ed60e6267233590981e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
// Copyright (c) 2010-2017 Intel Corporation
//
// 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 _STATS_TASK_H_
#define _STATS_TASK_H_

#include <inttypes.h>

#include "clock.h"

/* The struct task_stats is read/write from the task itself and
   read-only from the core that collects the stats. Since only the
   task executing the actual work ever modifies the stats, no locking
   is required. Both a read and a write are atomic (assuming the
   correct alignment). From this, it followed that the statistics can
   be incremented directly by the task itself. In cases where these
   assumptions do not hold, a possible solution (although slightly
   less accurate) would be to keep accumulate statistics temporarily
   in a separate structure and periodically copying the statistics to
   the statistics core through atomic primitives, for example through
   rte_atomic32_set(). The accuracy would be determined by the
   frequency at which the statistics are transferred to the statistics
   core. */

struct task_rt_stats {
	uint32_t	rx_pkt_count;
	uint32_t	tx_pkt_count;
	uint32_t	drop_tx_fail;
	uint32_t	drop_discard;
	uint32_t        drop_handled;
	uint32_t	idle_cycles;
	uint64_t        rx_bytes;
	uint64_t        tx_bytes;
	uint64_t        drop_bytes;
	uint64_t        rx_non_dp;
	uint64_t        tx_non_dp;
} __attribute__((packed)) __rte_cache_aligned;

#ifdef PROX_STATS
#define TASK_STATS_ADD_IDLE(stats, cycles) do {				\
		(stats)->idle_cycles += (cycles) + rdtsc_overhead_stats; \
	} while(0)							\

#define TASK_STATS_ADD_TX(stats, ntx) do {	\
		(stats)->tx_pkt_count += ntx;	\
	} while(0)				\

#define TASK_STATS_ADD_DROP_TX_FAIL(stats, ntx) do {	\
		(stats)->drop_tx_fail += ntx;		\
	} while(0)					\

#define TASK_STATS_ADD_DROP_HANDLED(stats, ntx) do {	\
		(stats)->drop_handled += ntx;		\
	} while(0)					\

#define TASK_STATS_ADD_DROP_DISCARD(stats, ntx) do {	\
		(stats)->drop_discard += ntx;		\
	} while(0)					\

#define TASK_STATS_ADD_RX(stats, ntx) do {	\
		(stats)->rx_pkt_count += ntx;	\
	} while (0)				\

#define TASK_STATS_ADD_RX_NON_DP(stats, ntx) do {    	\
		(stats)->rx_non_dp += ntx;             \
	} while(0)

#define TASK_STATS_ADD_TX_NON_DP(stats, ntx) do {     	\
		(stats)->tx_non_dp += ntx;		\
	 } while(0)

#define TASK_STATS_ADD_RX_BYTES(stats, bytes) do {	\
		(stats)->rx_bytes += bytes;		\
	} while (0)					\

#define TASK_STATS_ADD_TX_BYTES(stats, bytes) do {	\
		(stats)->tx_bytes += bytes;		\
	} while (0)					\

#define TASK_STATS_ADD_DROP_BYTES(stats, bytes) do {	\
		(stats)->drop_bytes += bytes;		\
	} while (0)					\

#define START_EMPTY_MEASSURE() uint64_t cur_tsc = rte_rdtsc();
#else
#define TASK_STATS_ADD_IDLE(stats, cycles) do {} while(0)
#define TASK_STATS_ADD_TX(stats, ntx)  do {} while(0)
#define TASK_STATS_ADD_DROP_TX_FAIL(stats, ntx)  do {} while(0)
#define TASK_STATS_ADD_DROP_HANDLED(stats, ntx)  do {} while(0)
#define TASK_STATS_ADD_DROP_DISCARD(stats, ntx)  do {} while(0)
#define TASK_STATS_ADD_RX(stats, ntx)  do {} while(0)
#define TASK_STATS_ADD_RX_BYTES(stats, bytes)  do {} while(0)
#define TASK_STATS_ADD_TX_BYTES(stats, bytes)  do {} while(0)
#define TASK_STATS_ADD_DROP_BYTES(stats, bytes) do {} while(0)
#define START_EMPTY_MEASSURE()  do {} while(0)
#endif

struct task_stats_sample {
	uint64_t tsc;
	uint32_t tx_pkt_count;
	uint32_t drop_tx_fail;
	uint32_t drop_discard;
	uint32_t drop_handled;
	uint32_t rx_pkt_count;
	uint32_t empty_cycles;
	uint64_t rx_bytes;
	uint64_t tx_bytes;
	uint64_t drop_bytes;
	uint64_t rx_non_dp;
	uint64_t tx_non_dp;
};

struct task_stats {
	uint64_t tot_tx_pkt_count;
	uint64_t tot_drop_tx_fail;
	uint64_t tot_drop_discard;
	uint64_t tot_drop_handled;
	uint64_t tot_rx_pkt_count;
	uint64_t tot_tx_non_dp;
	uint64_t tot_rx_non_dp;

	struct task_stats_sample sample[2];

	struct task_rt_stats *stats;
	/* flags set if total RX/TX values need to be reported set at
	   initialization time, only need to access stats values in port */
	uint8_t flags;
};

void stats_task_reset(void);
void stats_task_post_proc(void);
void stats_task_update(void);
void stats_task_init(void);

int stats_get_n_tasks_tot(void);

struct task_stats *stats_get_task_stats(uint32_t lcore_id, uint32_t task_id);
struct task_stats_sample *stats_get_task_stats_sample(uint32_t lcore_id, uint32_t task_id, int last);
void stats_task_get_host_rx_tx_packets(uint64_t *rx, uint64_t *tx, uint64_t *tsc);

uint64_t stats_core_task_tot_rx(uint8_t lcore_id, uint8_t task_id);
uint64_t stats_core_task_tot_tx(uint8_t lcore_id, uint8_t task_id);
uint64_t stats_core_task_tot_drop(uint8_t lcore_id, uint8_t task_id);
uint64_t stats_core_task_last_tsc(uint8_t lcore_id, uint8_t task_id);
uint64_t stats_core_task_tot_rx_non_dp(uint8_t lcore_id, uint8_t task_id);
uint64_t stats_core_task_tot_tx_non_dp(uint8_t lcore_id, uint8_t task_id);

#endif /* _STATS_TASK_H_ */