Messages in this thread | | | Subject | Re: [PATCH RFC ticketlock] Auto-queued ticketlock | From | Davidlohr Bueso <> | Date | Tue, 11 Jun 2013 11:54:41 -0700 |
| |
On Tue, 2013-06-11 at 14:41 -0400, Waiman Long wrote: > On 06/11/2013 12:36 PM, Paul E. McKenney wrote: > > > >> I am a bit concern about the size of the head queue table itself. > >> RHEL6, for example, had defined CONFIG_NR_CPUS to be 4096 which mean > >> a table size of 256. Maybe it is better to dynamically allocate the > >> table at init time depending on the actual number of CPUs in the > >> system. > > But if your kernel is built for 4096 CPUs, the 32*256=8192 bytes of memory > > is way down in the noise. Systems that care about that small an amount > > of memory probably have a small enough number of CPUs that they can just > > turn off queueing at build time using CONFIG_TICKET_LOCK_QUEUED=n, right? > > My concern is more about the latency on the table scan than the actual > memory that was used. > > > > >>> +/* > >>> + * Return a pointer to the queue header associated with the specified lock, > >>> + * or return NULL if there is no queue for the lock or if the lock's queue > >>> + * is in transition. > >>> + */ > >>> +static struct tkt_q_head *tkt_q_find_head(arch_spinlock_t *asp) > >>> +{ > >>> + int i; > >>> + int start; > >>> + > >>> + start = i = tkt_q_hash(asp); > >>> + do > >>> + if (tkt_q_heads[i].ref == asp) > >>> + return&tkt_q_heads[i]; > >>> + while ((i = tkt_q_next_slot(i)) != start); > >>> + return NULL; > >>> +} > >> With a table size of 256 and you have to scan the whole table to > >> find the right head queue. This can be a significant overhead. I > >> will suggest setting a limiting of how many entries it scans before > >> it aborts rather than checking the whole table. > > But it will scan 256 entries only if there are 256 other locks in queued > > mode, which is -very- unlikely, even given 4096 CPUs. That said, if you > > show me that this results in a real latency problem on a real system, > > I would be happy to provide a way to limit the search. > > Looking at the code more carefully, the chance of actually scanning 256 > entries is very small. However, I now have some concern on the way you > set up the initial queue. > > +/* > + * Start handling a period of high contention by finding a queue to associate > + * with this lock. Returns true if successful (in which case we hold the > + * lock) and false otherwise (in which case we do -not- hold the lock). > + */ > +bool tkt_q_start_contend(arch_spinlock_t *asp, struct __raw_tickets inc) > +{ > + int i; > + int start; > + > + /* Hash the lock address to find a starting point. */ > + start = i = tkt_q_hash(asp); > + > + /* > + * Each pass through the following loop attempts to associate > + * the lock with the corresponding queue. > + */ > + do { > + /* > + * Use 0x1 to mark the queue in use, but also avoiding > + * any spinners trying to use it before we get it all > + * initialized. > + */ > + if (cmpxchg(&tkt_q_heads[i].ref, > + NULL, > + (arch_spinlock_t *)0x1) == NULL) { > + > + /* Succeeded, now go initialize it. */ > + return tkt_q_init_contend(i, asp, inc); > + } > + > + /* If someone beat us to it, go spin on their queue. */ > + if (ACCESS_ONCE(asp->tickets.head)& 0x1) > + return tkt_q_do_spin(asp, inc); > + } while ((i = tkt_q_next_slot(i)) != start); > + > + /* All the queues are in use, revert to spinning on the ticket lock. */ > + return false; > +} > + > > Unconditional cmpxchg() can be a source of high contention by itself. > Considering that 16 threads may be doing cmpxchg() more or less > simultaneously on the same cache line, it can cause a lot of contention. > It will be better if you check to see if tkt_q_heads[i] is NULL first > before doing cmpxchg.
Good point, we already noticed good benefits in mutexes and rwsems when using test and cmpxchg techniques.
Thanks, davidlohr
| |