[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] mem_event: use wait queue when ring is full
> On Thu, Dec 15, Andres Lagar-Cavilla wrote: > >> > - How many requests should foreign vcpus place in the ring if the >> guest >> > has more vcpus than available slots in the ring? Just a single one >> so >> > that foreigners can also make some progress? >> The idea is that foreign vcpus can place as many events as they want as >> long as each guest vcpu that is not blocked on a men event has room to >> send one men event. When we reach that border condition, no more foreign >> men events. >> >> The case for which there are way too many guest vcpus needs to be >> handled, >> either by capping the max number of vcpus for domains using a men event, >> or by growing the ring size. > > Right now the ring is one page, so it can not hold more than 64 entries. > If that ever changes, the accounting can be adjusted. > >> > - Should access and paging have the same rules for accounting? >> Absolutely. >> >> And both should use wait queues in extreme cases in which a guest vcpu >> with a single action generates multiple memory events. Given that when >> we >> hit a border condition the guest vcpu will place one event and be >> flagged >> VPF_mem_event_paused (or whatever that flag is named), if a guest vcpu >> generates another event when flagged, that's our queue for putting the >> vcpu on a wait queue. > > An extra flag is not needed. Can you elaborate? Which flag is not needed? And why? > > Below is an incremental patch (on top of v6) which does some accounting. > Its just compile tested. > > Olaf > > > diff -r 5d5d10e1568b xen/arch/x86/mm/mem_event.c > --- a/xen/arch/x86/mm/mem_event.c > +++ b/xen/arch/x86/mm/mem_event.c > @@ -114,6 +114,19 @@ static int mem_event_enable( > > med->pause_flag = pause_flag; > > + /* > + * Configure ring accounting: > + * Each guest vcpu should be able to place at least one request. > + * If there are more vcpus than available slots in the ring, not all > vcpus > + * can place requests in the ring anyway. A minimum (arbitrary) > number of > + * foreign requests will be allowed in this case. > + */ > + if ( d->max_vcpus < RING_SIZE(&med->front_ring) ) > + med->max_foreign = RING_SIZE(&med->front_ring) - d->max_vcpus; > + if ( med->max_foreign < 13 ) > + med->max_foreign = 13; Magic number! Why? More generally, does this patch apply on top of a previous patch? What's the context here? Thanks Andres > + med->max_target = RING_SIZE(&med->front_ring) - med->max_foreign; > + > init_waitqueue_head(&med->wq); > > /* Wake any VCPUs waiting for the ring to appear */ > @@ -147,23 +160,28 @@ static int mem_event_disable(struct mem_ > > static int _mem_event_put_request(struct domain *d, > struct mem_event_domain *med, > - mem_event_request_t *req) > + mem_event_request_t *req, > + int *done) > { > mem_event_front_ring_t *front_ring; > - int free_req, claimed_req; > + int free_req, claimed_req, ret; > RING_IDX req_prod; > > + if ( *done ) > + return 1; > + > mem_event_ring_lock(med); > > - free_req = RING_FREE_REQUESTS(&med->front_ring); > + front_ring = &med->front_ring; > + > /* Foreign requests must succeed because their vcpus can not sleep */ > claimed_req = med->foreign_producers; > + free_req = RING_FREE_REQUESTS(front_ring); > if ( !free_req || ( current->domain == d && free_req <= claimed_req ) > ) { > mem_event_ring_unlock(med); > return 0; > } > > - front_ring = &med->front_ring; > req_prod = front_ring->req_prod_pvt; > > if ( current->domain != d ) > @@ -176,9 +194,18 @@ static int _mem_event_put_request(struct > memcpy(RING_GET_REQUEST(front_ring, req_prod), req, sizeof(*req)); > req_prod++; > > + ret = 1; > + *done = 1; > + free_req--; > + > /* Update accounting */ > if ( current->domain == d ) > + { > med->target_producers--; > + /* Ring is full, no more requests from this vcpu, go to sleep */ > + if ( free_req < med->max_target ) > + ret = 0; > + } > else > med->foreign_producers--; > > @@ -190,19 +217,20 @@ static int _mem_event_put_request(struct > > notify_via_xen_event_channel(d, med->xen_port); > > - return 1; > + return ret; > } > > void mem_event_put_request(struct domain *d, struct mem_event_domain > *med, > mem_event_request_t *req) > { > + int done = 0; > /* Go to sleep if request came from guest */ > if (current->domain == d) { > - wait_event(med->wq, _mem_event_put_request(d, med, req)); > + wait_event(med->wq, _mem_event_put_request(d, med, req, &done)); > return; > } > /* Ring was full anyway, unable to sleep in non-guest context */ > - if (!_mem_event_put_request(d, med, req)) > + if (!_mem_event_put_request(d, med, req, &done)) > printk("Failed to put memreq: d %u t %x f %x gfn %lx\n", > d->domain_id, > req->type, req->flags, (unsigned long)req->gfn); > } > @@ -341,7 +369,8 @@ int mem_event_claim_slot(struct domain * > med->target_producers++; > ring_full = 0; > } > - else if ( med->foreign_producers + med->target_producers + 1 < > free_req ) > + else if ( med->foreign_producers + med->target_producers < free_req > && > + med->foreign_producers < med->max_foreign ) > { > med->foreign_producers++; > ring_full = 0; > diff -r 5d5d10e1568b xen/include/xen/sched.h > --- a/xen/include/xen/sched.h > +++ b/xen/include/xen/sched.h > @@ -184,8 +184,11 @@ struct mem_event_domain > { > /* ring lock */ > spinlock_t ring_lock; > - unsigned short foreign_producers; > - unsigned short target_producers; > + /* The ring has 64 entries */ > + unsigned char foreign_producers; > + unsigned char max_foreign; > + unsigned char target_producers; > + unsigned char max_target; > /* shared page */ > mem_event_shared_page_t *shared_page; > /* shared ring page */ > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |