Skip to content

Commit 11d2f7c

Browse files
author
Brendan Jackman
committed
Add pthread_barrier event
This is just like the barrier event except it actually uses pthread_barrier_wait instead of pthread_cond_wait and pthread_cond_broadcast. This alternative method may cause issues with killing rt-app, but is still desirable because it exercises different syscall usage patterns, which are used in real workloads. I have tried to explain the details of this in tutorial.txt Implementing this requires adding a `finalize` step to resource setup, because we need to know the number of threads that refer to the resource before we can call pthread_barrier_init.
1 parent a9a0c6c commit 11d2f7c

File tree

4 files changed

+110
-8
lines changed

4 files changed

+110
-8
lines changed

doc/tutorial.txt

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,55 @@ generates the following sequence:
521521
"unlock" : "SyncPointA" (internal mutex)
522522
}
523523

524-
* suspend : String. Block the calling thread until another thread wakes it up
524+
* pthread_barrier: String. Used exactly like barrier, however this actually uses
525+
pthread_barrier_wait. As discussed above, this is likely to cause problems with
526+
killing rt-app.
527+
528+
Why would you want this instead of 'barrier'? 'barrier' uses pthread_cond_wait
529+
and pthread_broadcast. Note that pthread_cond_wait is passed a mutex, and that
530+
this mutex must be held by the caller. pthread_cond_wait releases this mutex,
531+
and must re-acquire it before returning. That means that when multiple waiters
532+
are woken by a pthread_cond_broadcast, all but one of them would have to
533+
immediately go back to sleep, waiting on the mutex, before returning from
534+
pthread_cond_wait. Therefore pthread implementations use a different futex
535+
mechanism for pthread_cond_wait than for pthread_barrier_wait: instead of using
536+
FUTEX_WAKE to wake all the waiters, FUTEX_CMP_REQUEUE is used to wake _one_of
537+
the waiters, and _move_ the remaining waiters so that instead of waiting on the
538+
condition variable itself, they are now waiting on the mutex. When the first
539+
waiter is woken it will release the mutex before returning from
540+
pthread_cond_wait, which will wake the second waiter. When the second waiter
541+
releases the mutex, it will release the third waiter, and so on. This can impact
542+
scheduler behaviour - instead of waking up multiple threads from a single
543+
context we now wake one thread from each context:
544+
545+
Using 'pthread_barrier' event:
546+
547+
548+
Thread A | Thread B | Thread C
549+
=========================================================================================
550+
| | pthread_barrier_wait(&b)
551+
| pthread_barrier_wait(&b) |
552+
pthread_barrier_wait(&b) | |
553+
\--WAKES-->| # unblocked by A # |
554+
\--WAKES--------------------------------->| # unblocked by A #
555+
556+
557+
Using 'barrier' event:
558+
559+
560+
Thread A | Thread B | Thread C
561+
=========================================================================================
562+
| | pthread_cond_wait(&c, &m)
563+
| pthread_cond_wait(&c, &m) |
564+
pthread_cond_broadcast(&c) | |
565+
\--WAKES-->| # unblocked by A # |
566+
| \--WAKES-->| # unblocked by B #
567+
568+
569+
Therefore, you might want to use the pthread_barrier event even though it can
570+
cause problems with killing rt-app.
571+
572+
* Suspend : String. Block the calling thread until another thread wakes it up
525573
with resume. The String can be let empty as it will be filled by workgen with
526574
the right thread's name before starting the use case.
527575

src/rt-app.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,10 @@ static int run_event(event_data_t *event, int dry_run,
299299
}
300300
pthread_mutex_unlock(&(rdata->res.barrier.m_obj));
301301
break;
302+
case rtapp_pthread_barrier:
303+
log_debug("pthread_barrier %s", rdata->name);
304+
pthread_barrier_wait(&rdata->res.pthread_barrier.obj);
305+
break;
302306
case rtapp_sig_and_wait:
303307
log_debug("signal and wait %s", rdata->name);
304308
pthread_cond_signal(&(rdata->res.cond.obj));

src/rt-app_parse_config.c

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,19 @@ static void init_barrier_resource(rtapp_resource_t *data, const rtapp_options_t
238238
pthread_cond_init(&data->res.barrier.c_obj, NULL);
239239
}
240240

241+
static void finalize_pthread_barrier_resource(rtapp_resource_t *data, const rtapp_options_t *opts)
242+
{
243+
int err;
244+
int thread_count = data->res.pthread_barrier.thread_ref_count;
245+
246+
log_info(PIN3 "Finalize: %s pthread_barrier %d threads", data->name, thread_count);
247+
248+
err = pthread_barrier_init(&data->res.pthread_barrier.obj, NULL, thread_count);
249+
if (err) {
250+
perror("pthread_barrier_init");
251+
}
252+
}
253+
241254
static void
242255
init_resource_data(const char *name, int type, int idx, const rtapp_options_t *opts)
243256
{
@@ -267,6 +280,9 @@ init_resource_data(const char *name, int type, int idx, const rtapp_options_t *o
267280
case rtapp_barrier:
268281
init_barrier_resource(data, opts);
269282
break;
283+
case rtapp_pthread_barrier:
284+
/* Init all done in finalize_resources */
285+
break;
270286
default:
271287
break;
272288
}
@@ -357,6 +373,21 @@ static int get_resource_index(const char *name, int type, rtapp_options_t *opts)
357373
return i;
358374
}
359375

376+
static int finalize_resources(rtapp_options_t *opts)
377+
{
378+
int i;
379+
380+
for (i = 0; i < opts->nresources; i++) {
381+
switch (opts->resources[i].type) {
382+
case rtapp_pthread_barrier:
383+
finalize_pthread_barrier_resource(&opts->resources[i], opts);
384+
break;
385+
default:
386+
break;
387+
}
388+
}
389+
}
390+
360391
static char* create_unique_name(char *tmp, int size, const char* ref, long tag)
361392
{
362393
snprintf(tmp, size, "%s%lx", ref, (long)(tag));
@@ -499,21 +530,30 @@ parse_thread_event_data(char *name, struct json_object *obj,
499530
return;
500531
}
501532

502-
if (!strncmp(name, "barrier", strlen("barrier"))) {
533+
if (!strncmp(name, "barrier", strlen("barrier")) ||
534+
!strncmp(name, "pthread_barrier", strlen("pthread_barrier"))) {
535+
int thread_count;
503536

504537
if (!json_object_is_type(obj, json_type_string))
505538
goto unknown_event;
506539

507-
data->type = rtapp_barrier;
540+
if (!strncmp(name, "barrier", strlen("barrier")))
541+
data->type = rtapp_barrier;
542+
else
543+
data->type = rtapp_pthread_barrier;
508544

509545
ref = json_object_get_string(obj);
510-
i = get_resource_index(ref, rtapp_barrier, opts);
546+
i = get_resource_index(ref, data->type, opts);
511547

512548
data->res = i;
513549
rdata = &(opts->resources[data->res]);
514-
rdata->res.barrier.waiting += 1;
550+
if (data->type == rtapp_barrier)
551+
thread_count = ++rdata->res.barrier.waiting;
552+
else
553+
thread_count = ++rdata->res.pthread_barrier.thread_ref_count;
515554

516-
log_info(PIN2 "type %d target %s [%d] %d users so far", data->type, rdata->name, rdata->index, rdata->res.barrier.waiting);
555+
log_info(PIN2 "type %d target %s [%d] %d users so far",
556+
data->type, rdata->name, rdata->index, thread_count);
517557
return;
518558
}
519559

@@ -631,6 +671,7 @@ static char *events[] = {
631671
"iorun",
632672
"yield",
633673
"barrier",
674+
"pthread_barrier",
634675
NULL
635676
};
636677

@@ -1051,7 +1092,8 @@ get_opts_from_json_object(struct json_object *root, rtapp_options_t *opts)
10511092
parse_tasks(tasks, opts);
10521093
json_object_put(tasks);
10531094
log_info(PFX "Free json objects");
1054-
1095+
log_info(PFX "Finalize resources");
1096+
finalize_resources(opts);
10551097
}
10561098

10571099
void

src/rt-app_types.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ typedef enum resource_t
7272
rtapp_iorun,
7373
rtapp_runtime,
7474
rtapp_yield,
75-
rtapp_barrier
75+
rtapp_barrier,
76+
rtapp_pthread_barrier
7677
} resource_t;
7778

7879
struct _rtapp_mutex {
@@ -99,6 +100,12 @@ struct _rtapp_barrier_like {
99100
pthread_cond_t c_obj;
100101
};
101102

103+
struct _rtapp_pthread_barrier {
104+
pthread_barrier_t obj;
105+
/* Number of threads that refer to this barrier */
106+
int thread_ref_count;
107+
};
108+
102109
struct _rtapp_signal {
103110
pthread_cond_t *target;
104111
};
@@ -128,6 +135,7 @@ typedef struct _rtapp_resource_t {
128135
struct _rtapp_iomem_buf buf;
129136
struct _rtapp_iodev dev;
130137
struct _rtapp_barrier_like barrier;
138+
struct _rtapp_pthread_barrier pthread_barrier;
131139
} res;
132140
int index;
133141
resource_t type;

0 commit comments

Comments
 (0)