From: Longjun Tang <[email protected]> To facilitate tracking the status of virtqueue during rx/tx and interrupt response, add trace point at corresponding func.
Also,to avoid perf hured,it olny available under debug condition. Signed-off-by: Longjun Tang <[email protected]> --- v1: I did some tests with iperf3, as follow: host <---> vm oringnal: rx pps: 90915 rx bitrate: 28.5 Gbits/s tx pps: 54659 tx bitrate: 26.4 Gbits/s added trace: rx pps: 76810 rx bitrate: 26.7 Gbits/s tx pps: 54455 tx bitrate: 26.4 Gbits/s Based on the results of the above tests, adding tracing has a performance hurt, especially on the rx side. Therefore, these traces should only be added to the debug virtio_net. When these traces are needed, uncomment the DEBUG macro definition in driver/net/virtio_net.c. --- drivers/net/virtio_net.c | 21 ++++- drivers/net/virtio_net_trace.h | 124 ++++++++++++++++++++++++++ drivers/virtio/virtio_ring.c | 155 -------------------------------- include/linux/virtio_ring.h | 156 +++++++++++++++++++++++++++++++++ 4 files changed, 297 insertions(+), 159 deletions(-) create mode 100644 drivers/net/virtio_net_trace.h diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 22d894101c01..fabd3e8acb36 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -27,6 +27,11 @@ #include <net/netdev_queues.h> #include <net/xdp_sock_drv.h> +#if defined(DEBUG) +#define CREATE_TRACE_POINTS +#include "virtio_net_trace.h" +#endif + static int napi_weight = NAPI_POLL_WEIGHT; module_param(napi_weight, int, 0444); @@ -795,7 +800,9 @@ static void skb_xmit_done(struct virtqueue *vq) unsigned int index = vq2txq(vq); struct send_queue *sq = &vi->sq[index]; struct napi_struct *napi = &sq->napi; - +#if defined(DEBUG) + trace_skb_xmit_done(napi, vq); +#endif /* Suppress further interrupts. */ virtqueue_disable_cb(vq); @@ -2671,7 +2678,9 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq, if (unlikely(!skb)) return; - +#if defined(DEBUG) + trace_receive_buf(rq->vq, skb); +#endif virtnet_receive_done(vi, rq, skb, flags); } @@ -2877,7 +2886,9 @@ static void skb_recv_done(struct virtqueue *rvq) { struct virtnet_info *vi = rvq->vdev->priv; struct receive_queue *rq = &vi->rq[vq2rxq(rvq)]; - +#if defined(DEBUG) + trace_skb_recv_done(&rq->napi, rvq); +#endif rq->calls++; virtqueue_napi_schedule(&rq->napi, rvq); } @@ -3389,7 +3400,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) /* timestamp packet in software */ skb_tx_timestamp(skb); - +#if defined(DEBUG) + trace_start_xmit(sq->vq, skb); +#endif /* Try to transmit */ err = xmit_skb(sq, skb, !use_napi); diff --git a/drivers/net/virtio_net_trace.h b/drivers/net/virtio_net_trace.h new file mode 100644 index 000000000000..0a008cb8f51d --- /dev/null +++ b/drivers/net/virtio_net_trace.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#if defined(DEBUG) + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM virtio_net + +#if !defined(_TRACE_VIRTIO_NET_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_VIRTIO_NET_H + +#include <linux/virtio.h> +#include <linux/tracepoint.h> +#include <linux/virtio_ring.h> + +DECLARE_EVENT_CLASS(virtio_net_rxtx_temp, + + TP_PROTO(struct virtqueue *vq, const struct sk_buff *skb), + + TP_ARGS(vq, skb), + + TP_STRUCT__entry( + __string( name, vq->name ) + __field( unsigned int, num_free ) + __field( unsigned int, index ) + __field( bool, packed_ring ) + __field( bool, broken ) + __field( bool, event ) + __field( u16, last_used_idx ) + __field( __virtio16, avail_flags ) + __field( __virtio16, avail_idx ) + __field( __virtio16, used_idx ) + __field( const void *, skbaddr ) + ), + + TP_fast_assign( + __entry->skbaddr = skb; + + __assign_str(name); + __entry->num_free = vq->num_free; + __entry->index = vq->index; + + struct vring_virtqueue *vvq; + + vvq = container_of_const(vq, struct vring_virtqueue, vq); + + __entry->packed_ring = vvq->packed_ring; + __entry->broken = vvq->broken; + __entry->event = vvq->event; + if (!vvq->packed_ring) { + __entry->last_used_idx = vvq->last_used_idx; + __entry->avail_flags = vvq->split.vring.avail->flags; + __entry->avail_idx = vvq->split.vring.avail->idx; + __entry->used_idx = vvq->split.vring.used->idx; + } + ), + + TP_printk("skbaddr=%p vq=%s num_free=%u index=%u packed=%d broken=%d event=%d last_used_idx=%u avail_flags=%u avail_idx=%u used_idx=%u", + __entry->skbaddr, __get_str(name), __entry->num_free, __entry->index, + __entry->packed_ring, __entry->broken, __entry->event, __entry->last_used_idx, + __entry->avail_flags, __entry->avail_idx, __entry->used_idx) +) + +DEFINE_EVENT(virtio_net_rxtx_temp, receive_buf, + + TP_PROTO(struct virtqueue *vq, const struct sk_buff *skb), + + TP_ARGS(vq, skb) +); + +DEFINE_EVENT(virtio_net_rxtx_temp, start_xmit, + + TP_PROTO(struct virtqueue *vq, const struct sk_buff *skb), + + TP_ARGS(vq, skb) +); + +DECLARE_EVENT_CLASS(virtio_net_int_temp, + + TP_PROTO(struct napi_struct *napi, struct virtqueue *vq), + + TP_ARGS(napi, vq), + + TP_STRUCT__entry( + __string( dev_name, napi->dev->name ) + __string( vq_name, vq->name) + __field( u32, napi_id ) + __field( int, weight ) + ), + + TP_fast_assign( + __assign_str(dev_name); + __assign_str(vq_name); + __entry->napi_id = napi->napi_id; + __entry->weight = napi->weight; + ), + + TP_printk("dev=%s vq=%s napi_id=%u weight=%d", + __get_str(dev_name), __get_str(vq_name), __entry->napi_id, __entry->weight) +) + +DEFINE_EVENT(virtio_net_int_temp, skb_xmit_done, + + TP_PROTO(struct napi_struct *napi, struct virtqueue *vq), + + TP_ARGS(napi, vq) +); + +DEFINE_EVENT(virtio_net_int_temp, skb_recv_done, + + TP_PROTO(struct napi_struct *napi, struct virtqueue *vq), + + TP_ARGS(napi, vq) +); + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/net/ +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE virtio_net_trace + +#endif /* _TRACE_VIRTIO_NET_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> + +#endif diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index ddab68959671..d413ebb42729 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -67,161 +67,6 @@ #define LAST_ADD_TIME_INVALID(vq) #endif -struct vring_desc_state_split { - void *data; /* Data for callback. */ - - /* Indirect desc table and extra table, if any. These two will be - * allocated together. So we won't stress more to the memory allocator. - */ - struct vring_desc *indir_desc; -}; - -struct vring_desc_state_packed { - void *data; /* Data for callback. */ - - /* Indirect desc table and extra table, if any. These two will be - * allocated together. So we won't stress more to the memory allocator. - */ - struct vring_packed_desc *indir_desc; - u16 num; /* Descriptor list length. */ - u16 last; /* The last desc state in a list. */ -}; - -struct vring_desc_extra { - dma_addr_t addr; /* Descriptor DMA addr. */ - u32 len; /* Descriptor length. */ - u16 flags; /* Descriptor flags. */ - u16 next; /* The next desc state in a list. */ -}; - -struct vring_virtqueue_split { - /* Actual memory layout for this queue. */ - struct vring vring; - - /* Last written value to avail->flags */ - u16 avail_flags_shadow; - - /* - * Last written value to avail->idx in - * guest byte order. - */ - u16 avail_idx_shadow; - - /* Per-descriptor state. */ - struct vring_desc_state_split *desc_state; - struct vring_desc_extra *desc_extra; - - /* DMA address and size information */ - dma_addr_t queue_dma_addr; - size_t queue_size_in_bytes; - - /* - * The parameters for creating vrings are reserved for creating new - * vring. - */ - u32 vring_align; - bool may_reduce_num; -}; - -struct vring_virtqueue_packed { - /* Actual memory layout for this queue. */ - struct { - unsigned int num; - struct vring_packed_desc *desc; - struct vring_packed_desc_event *driver; - struct vring_packed_desc_event *device; - } vring; - - /* Driver ring wrap counter. */ - bool avail_wrap_counter; - - /* Avail used flags. */ - u16 avail_used_flags; - - /* Index of the next avail descriptor. */ - u16 next_avail_idx; - - /* - * Last written value to driver->flags in - * guest byte order. - */ - u16 event_flags_shadow; - - /* Per-descriptor state. */ - struct vring_desc_state_packed *desc_state; - struct vring_desc_extra *desc_extra; - - /* DMA address and size information */ - dma_addr_t ring_dma_addr; - dma_addr_t driver_event_dma_addr; - dma_addr_t device_event_dma_addr; - size_t ring_size_in_bytes; - size_t event_size_in_bytes; -}; - -struct vring_virtqueue { - struct virtqueue vq; - - /* Is this a packed ring? */ - bool packed_ring; - - /* Is DMA API used? */ - bool use_map_api; - - /* Can we use weak barriers? */ - bool weak_barriers; - - /* Other side has made a mess, don't try any more. */ - bool broken; - - /* Host supports indirect buffers */ - bool indirect; - - /* Host publishes avail event idx */ - bool event; - - /* Head of free buffer list. */ - unsigned int free_head; - /* Number we've added since last sync. */ - unsigned int num_added; - - /* Last used index we've seen. - * for split ring, it just contains last used index - * for packed ring: - * bits up to VRING_PACKED_EVENT_F_WRAP_CTR include the last used index. - * bits from VRING_PACKED_EVENT_F_WRAP_CTR include the used wrap counter. - */ - u16 last_used_idx; - - /* Hint for event idx: already triggered no need to disable. */ - bool event_triggered; - - union { - /* Available for split ring */ - struct vring_virtqueue_split split; - - /* Available for packed ring */ - struct vring_virtqueue_packed packed; - }; - - /* How to notify other side. FIXME: commonalize hcalls! */ - bool (*notify)(struct virtqueue *vq); - - /* DMA, allocation, and size information */ - bool we_own_ring; - - union virtio_map map; - -#ifdef DEBUG - /* They're supposed to lock for us. */ - unsigned int in_use; - - /* Figure out if their kicks are too delayed. */ - bool last_add_time_valid; - ktime_t last_add_time; -#endif -}; - static struct vring_desc_extra *vring_alloc_desc_extra(unsigned int num); static void vring_free(struct virtqueue *_vq); diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h index c97a12c1cda3..1442a02209ec 100644 --- a/include/linux/virtio_ring.h +++ b/include/linux/virtio_ring.h @@ -121,4 +121,160 @@ void vring_transport_features(struct virtio_device *vdev); irqreturn_t vring_interrupt(int irq, void *_vq); u32 vring_notification_data(struct virtqueue *_vq); + +struct vring_desc_state_split { + void *data; /* Data for callback. */ + + /* Indirect desc table and extra table, if any. These two will be + * allocated together. So we won't stress more to the memory allocator. + */ + struct vring_desc *indir_desc; +}; + +struct vring_desc_state_packed { + void *data; /* Data for callback. */ + + /* Indirect desc table and extra table, if any. These two will be + * allocated together. So we won't stress more to the memory allocator. + */ + struct vring_packed_desc *indir_desc; + u16 num; /* Descriptor list length. */ + u16 last; /* The last desc state in a list. */ +}; + +struct vring_desc_extra { + dma_addr_t addr; /* Descriptor DMA addr. */ + u32 len; /* Descriptor length. */ + u16 flags; /* Descriptor flags. */ + u16 next; /* The next desc state in a list. */ +}; + +struct vring_virtqueue_split { + /* Actual memory layout for this queue. */ + struct vring vring; + + /* Last written value to avail->flags */ + u16 avail_flags_shadow; + + /* + * Last written value to avail->idx in + * guest byte order. + */ + u16 avail_idx_shadow; + + /* Per-descriptor state. */ + struct vring_desc_state_split *desc_state; + struct vring_desc_extra *desc_extra; + + /* DMA address and size information */ + dma_addr_t queue_dma_addr; + size_t queue_size_in_bytes; + + /* + * The parameters for creating vrings are reserved for creating new + * vring. + */ + u32 vring_align; + bool may_reduce_num; +}; + +struct vring_virtqueue_packed { + /* Actual memory layout for this queue. */ + struct { + unsigned int num; + struct vring_packed_desc *desc; + struct vring_packed_desc_event *driver; + struct vring_packed_desc_event *device; + } vring; + + /* Driver ring wrap counter. */ + bool avail_wrap_counter; + + /* Avail used flags. */ + u16 avail_used_flags; + + /* Index of the next avail descriptor. */ + u16 next_avail_idx; + + /* + * Last written value to driver->flags in + * guest byte order. + */ + u16 event_flags_shadow; + + /* Per-descriptor state. */ + struct vring_desc_state_packed *desc_state; + struct vring_desc_extra *desc_extra; + + /* DMA address and size information */ + dma_addr_t ring_dma_addr; + dma_addr_t driver_event_dma_addr; + dma_addr_t device_event_dma_addr; + size_t ring_size_in_bytes; + size_t event_size_in_bytes; +}; + +struct vring_virtqueue { + struct virtqueue vq; + + /* Is this a packed ring? */ + bool packed_ring; + + /* Is DMA API used? */ + bool use_map_api; + + /* Can we use weak barriers? */ + bool weak_barriers; + + /* Other side has made a mess, don't try any more. */ + bool broken; + + /* Host supports indirect buffers */ + bool indirect; + + /* Host publishes avail event idx */ + bool event; + + /* Head of free buffer list. */ + unsigned int free_head; + /* Number we've added since last sync. */ + unsigned int num_added; + + /* Last used index we've seen. + * for split ring, it just contains last used index + * for packed ring: + * bits up to VRING_PACKED_EVENT_F_WRAP_CTR include the last used index. + * bits from VRING_PACKED_EVENT_F_WRAP_CTR include the used wrap counter. + */ + u16 last_used_idx; + + /* Hint for event idx: already triggered no need to disable. */ + bool event_triggered; + + union { + /* Available for split ring */ + struct vring_virtqueue_split split; + + /* Available for packed ring */ + struct vring_virtqueue_packed packed; + }; + + /* How to notify other side. FIXME: commonalize hcalls! */ + bool (*notify)(struct virtqueue *vq); + + /* DMA, allocation, and size information */ + bool we_own_ring; + + union virtio_map map; + +#ifdef DEBUG + /* They're supposed to lock for us. */ + unsigned int in_use; + + /* Figure out if their kicks are too delayed. */ + bool last_add_time_valid; + ktime_t last_add_time; +#endif +}; + #endif /* _LINUX_VIRTIO_RING_H */ -- 2.48.1
