Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vhost: cache used event for better performance

When event index was enabled, we need to fetch used event from
userspace memory each time. This userspace fetch (with memory
barrier) could be saved sometime when 1) caching used event and 2)
if used event is ahead of new and old to new updating does not cross
it, we're sure there's no need to notify guest.

This will be useful for heavy tx load e.g guest pktgen test with Linux
driver shows ~3.5% improvement.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Jason Wang and committed by
Michael S. Tsirkin
809ecb9b 6c083c2b

+25 -6
+22 -6
drivers/vhost/vhost.c
··· 290 290 vq->avail = NULL; 291 291 vq->used = NULL; 292 292 vq->last_avail_idx = 0; 293 + vq->last_used_event = 0; 293 294 vq->avail_idx = 0; 294 295 vq->last_used_idx = 0; 295 296 vq->signalled_used = 0; ··· 1325 1324 r = -EINVAL; 1326 1325 break; 1327 1326 } 1328 - vq->last_avail_idx = s.num; 1327 + vq->last_avail_idx = vq->last_used_event = s.num; 1329 1328 /* Forget the cached index value. */ 1330 1329 vq->avail_idx = vq->last_avail_idx; 1331 1330 break; ··· 2160 2159 __u16 old, new; 2161 2160 __virtio16 event; 2162 2161 bool v; 2163 - /* Flush out used index updates. This is paired 2164 - * with the barrier that the Guest executes when enabling 2165 - * interrupts. */ 2166 - smp_mb(); 2167 2162 2168 2163 if (vhost_has_feature(vq, VIRTIO_F_NOTIFY_ON_EMPTY) && 2169 2164 unlikely(vq->avail_idx == vq->last_avail_idx)) ··· 2167 2170 2168 2171 if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) { 2169 2172 __virtio16 flags; 2173 + /* Flush out used index updates. This is paired 2174 + * with the barrier that the Guest executes when enabling 2175 + * interrupts. */ 2176 + smp_mb(); 2170 2177 if (vhost_get_user(vq, flags, &vq->avail->flags)) { 2171 2178 vq_err(vq, "Failed to get flags"); 2172 2179 return true; ··· 2185 2184 if (unlikely(!v)) 2186 2185 return true; 2187 2186 2187 + /* We're sure if the following conditions are met, there's no 2188 + * need to notify guest: 2189 + * 1) cached used event is ahead of new 2190 + * 2) old to new updating does not cross cached used event. */ 2191 + if (vring_need_event(vq->last_used_event, new + vq->num, new) && 2192 + !vring_need_event(vq->last_used_event, new, old)) 2193 + return false; 2194 + 2195 + /* Flush out used index updates. This is paired 2196 + * with the barrier that the Guest executes when enabling 2197 + * interrupts. */ 2198 + smp_mb(); 2199 + 2188 2200 if (vhost_get_user(vq, event, vhost_used_event(vq))) { 2189 2201 vq_err(vq, "Failed to get used event idx"); 2190 2202 return true; 2191 2203 } 2192 - return vring_need_event(vhost16_to_cpu(vq, event), new, old); 2204 + vq->last_used_event = vhost16_to_cpu(vq, event); 2205 + 2206 + return vring_need_event(vq->last_used_event, new, old); 2193 2207 } 2194 2208 2195 2209 /* This actually signals the guest, using eventfd. */
+3
drivers/vhost/vhost.h
··· 107 107 /* Last index we used. */ 108 108 u16 last_used_idx; 109 109 110 + /* Last used evet we've seen */ 111 + u16 last_used_event; 112 + 110 113 /* Used flags */ 111 114 u16 used_flags; 112 115