X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fovs-thread.c;h=19edf8ff14da2750a00f06fa3b981b3301a281d2;hb=c5cf10598f8c9f4428291e9df3ecd72a05fb1ccf;hp=0dc5585474d6b98deb35d0b3807ad555561e9b8a;hpb=0f2ea84841e1689ebf18e2260819e6493dbf2356;p=sliver-openvswitch.git diff --git a/lib/ovs-thread.c b/lib/ovs-thread.c index 0dc558547..19edf8ff1 100644 --- a/lib/ovs-thread.c +++ b/lib/ovs-thread.c @@ -240,7 +240,10 @@ xpthread_barrier_wait(pthread_barrier_t *barrier) { int error; + ovsrcu_quiesce_start(); error = pthread_barrier_wait(barrier); + ovsrcu_quiesce_end(); + if (error && OVS_UNLIKELY(error != PTHREAD_BARRIER_SERIAL_THREAD)) { ovs_abort(error, "pthread_barrier_wait failed"); } @@ -253,6 +256,7 @@ DEFINE_EXTERN_PER_THREAD_DATA(ovsthread_id, 0); struct ovsthread_aux { void *(*start)(void *); void *arg; + char name[16]; }; static void * @@ -270,13 +274,18 @@ ovsthread_wrapper(void *aux_) aux = *auxp; free(auxp); + /* The order of the following calls is important, because + * ovsrcu_quiesce_end() saves a copy of the thread name. */ + set_subprogram_name("%s%u", aux.name, id); ovsrcu_quiesce_end(); + return aux.start(aux.arg); } -void -xpthread_create(pthread_t *threadp, pthread_attr_t *attr, - void *(*start)(void *), void *arg) +/* Starts a thread that calls 'start(arg)'. Sets the thread's name to 'name' + * (suffixed by its ovsthread_id()). Returns the new thread's pthread_t. */ +pthread_t +ovs_thread_create(const char *name, void *(*start)(void *), void *arg) { struct ovsthread_aux *aux; pthread_t thread; @@ -289,12 +298,13 @@ xpthread_create(pthread_t *threadp, pthread_attr_t *attr, aux = xmalloc(sizeof *aux); aux->start = start; aux->arg = arg; + ovs_strlcpy(aux->name, name, sizeof aux->name); - error = pthread_create(threadp ? threadp : &thread, attr, - ovsthread_wrapper, aux); + error = pthread_create(&thread, NULL, ovsthread_wrapper, aux); if (error) { ovs_abort(error, "pthread_create failed"); } + return thread; } bool @@ -379,83 +389,53 @@ may_fork(void) return !must_not_fork; } -/* ovsthread_counter. - * - * We implement the counter as an array of N_COUNTERS individual counters, each - * with its own lock. Each thread uses one of the counters chosen based on a - * hash of the thread's ID, the idea being that, statistically, different - * threads will tend to use different counters and therefore avoid - * interfering with each other. - * - * Undoubtedly, better implementations are possible. */ +/* ovsthread_stats. */ -/* Basic counter structure. */ -struct ovsthread_counter__ { - struct ovs_mutex mutex; - unsigned long long int value; -}; - -/* Pad the basic counter structure to 64 bytes to avoid cache line - * interference. */ -struct ovsthread_counter { - struct ovsthread_counter__ c; - char pad[ROUND_UP(sizeof(struct ovsthread_counter__), 64) - - sizeof(struct ovsthread_counter__)]; -}; - -#define N_COUNTERS 16 - -struct ovsthread_counter * -ovsthread_counter_create(void) +void +ovsthread_stats_init(struct ovsthread_stats *stats) { - struct ovsthread_counter *c; int i; - c = xmalloc(N_COUNTERS * sizeof *c); - for (i = 0; i < N_COUNTERS; i++) { - ovs_mutex_init(&c[i].c.mutex); - c[i].c.value = 0; + ovs_mutex_init(&stats->mutex); + for (i = 0; i < ARRAY_SIZE(stats->buckets); i++) { + stats->buckets[i] = NULL; } - return c; } void -ovsthread_counter_destroy(struct ovsthread_counter *c) +ovsthread_stats_destroy(struct ovsthread_stats *stats) { - if (c) { - int i; - - for (i = 0; i < N_COUNTERS; i++) { - ovs_mutex_destroy(&c[i].c.mutex); - } - free(c); - } + ovs_mutex_destroy(&stats->mutex); } -void -ovsthread_counter_inc(struct ovsthread_counter *c, unsigned long long int n) +void * +ovsthread_stats_bucket_get(struct ovsthread_stats *stats, + void *(*new_bucket)(void)) { - c = &c[hash_int(ovsthread_id_self(), 0) % N_COUNTERS]; - - ovs_mutex_lock(&c->c.mutex); - c->c.value += n; - ovs_mutex_unlock(&c->c.mutex); + unsigned int idx = ovsthread_id_self() & (ARRAY_SIZE(stats->buckets) - 1); + void *bucket = stats->buckets[idx]; + if (!bucket) { + ovs_mutex_lock(&stats->mutex); + bucket = stats->buckets[idx]; + if (!bucket) { + bucket = stats->buckets[idx] = new_bucket(); + } + ovs_mutex_unlock(&stats->mutex); + } + return bucket; } -unsigned long long int -ovsthread_counter_read(const struct ovsthread_counter *c) +size_t +ovs_thread_stats_next_bucket(const struct ovsthread_stats *stats, size_t i) { - unsigned long long int sum; - int i; - - sum = 0; - for (i = 0; i < N_COUNTERS; i++) { - ovs_mutex_lock(&c[i].c.mutex); - sum += c[i].c.value; - ovs_mutex_unlock(&c[i].c.mutex); + for (; i < ARRAY_SIZE(stats->buckets); i++) { + if (stats->buckets[i]) { + break; + } } - return sum; + return i; } + /* Parses /proc/cpuinfo for the total number of physical cores on this system * across all CPU packages, not counting hyper-threads.