Skip to content

Commit

Permalink
Merge affinity
Browse files Browse the repository at this point in the history
  • Loading branch information
fryguybob committed Jan 2, 2015
2 parents 2e3e2be + 09f8abd commit d50ea1f
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 20 deletions.
5 changes: 5 additions & 0 deletions includes/rts/Flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ struct PAR_FLAGS {
* (zero disables) */

rtsBool setAffinity; /* force thread affinity with CPUs */
char* setAffinityTopology;
/* Allow the user to specify a particular
* assignment of capabilites to CPUs */
nat setAffinityTopologySize;
nat setAffinityTopologyCount;
};
#endif /* THREADED_RTS */

Expand Down
125 changes: 114 additions & 11 deletions rts/RtsFlags.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
*
* ---------------------------------------------------------------------------*/

#if defined(__linux__) || defined(__GLIBC__)
/* We want GNU extensions in DEBUG mode for mutex error checking */
/* We also want the affinity API, which requires _GNU_SOURCE */
#define _GNU_SOURCE
#endif

#include "PosixSource.h"
#include "Rts.h"

Expand All @@ -19,6 +25,10 @@
#include <ctype.h>
#endif

#if defined(HAVE_SCHED_H)
#include <sched.h>
#endif

#include <string.h>

#ifdef HAVE_UNISTD_H
Expand Down Expand Up @@ -80,6 +90,10 @@ static void bad_option (const char *s);
static void read_trace_flags(char *arg);
#endif

#if defined(THREADED_RTS) && defined(HAVE_SCHED_H)
static rtsBool readAffinityTopology(const char* file);
#endif

static void errorUsage (void) GNU_ATTRIBUTE(__noreturn__);

static char * copyArg (char *arg);
Expand Down Expand Up @@ -209,6 +223,9 @@ void initRtsFlagsDefaults(void)
RtsFlags.ParFlags.parGcLoadBalancingGen = 1;
RtsFlags.ParFlags.parGcNoSyncWithIdle = 0;
RtsFlags.ParFlags.setAffinity = 0;
RtsFlags.ParFlags.setAffinityTopology = NULL;
RtsFlags.ParFlags.setAffinityTopologySize = 0;
RtsFlags.ParFlags.setAffinityTopologyCount = 0;
#endif

#if defined(THREADED_RTS)
Expand Down Expand Up @@ -370,17 +387,22 @@ usage_text[] = {
"",
#endif /* DEBUG */
#if defined(THREADED_RTS) && !defined(NOSMP)
" -N[<n>] Use <n> processors (default: 1, -N alone determines",
" the number of processors to use automatically)",
" -qg[<n>] Use parallel GC only for generations >= <n>",
" (default: 0, -qg alone turns off parallel GC)",
" -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
" (default: 1, -qb alone turns off load-balancing)",
" -qa Use the OS to set thread affinity (experimental)",
" -qm Don't automatically migrate threads between CPUs",
" -qi<n> If a processor has been idle for the last <n> GCs, do not",
" wake it up for a non-load-balancing parallel GC.",
" (0 disables, default: 0)",
" -N[<n>] Use <n> processors (default: 1, -N alone determines",
" the number of processors to use automatically)",
" -qg[<n>] Use parallel GC only for generations >= <n>",
" (default: 0, -qg alone turns off parallel GC)",
" -qb[<n>] Use load-balancing in the parallel GC only for generations >= <n>",
" (default: 1, -qb alone turns off load-balancing)",
#if defined(HAVE_SCHED_H)
" -qa[<file>] Use the OS to set thread affinity (experimental)",
" (optional file specifies affinity masks)",
#else
" -qa Use the OS to set thread affinity (experimental)",
#endif
" -qm Don't automatically migrate threads between CPUs",
" -qi<n> If a processor has been idle for the last <n> GCs, do not",
" wake it up for a non-load-balancing parallel GC.",
" (0 disables, default: 0)",
#endif
" --install-signal-handlers=<yes|no>",
" Install signal handlers (default: yes)",
Expand Down Expand Up @@ -1247,6 +1269,14 @@ error = rtsTrue;
break;
case 'a':
RtsFlags.ParFlags.setAffinity = rtsTrue;
#if defined(HAVE_SCHED_H)
if (rts_argv[arg][3] != '\0') {
if (!readAffinityTopology(rts_argv[arg]+3)) {
errorBelch("failed to parse topology: %s", rts_argv[arg]+3);
error = rtsTrue;
}
}
#endif
break;
case 'm':
RtsFlags.ParFlags.migrate = rtsFalse;
Expand Down Expand Up @@ -1654,6 +1684,79 @@ static void read_trace_flags(char *arg)
}
#endif

#if defined(THREADED_RTS) && defined(HAVE_SCHED_H)
static rtsBool readAffinityTopology(const char* file)
{
FILE *topo;

if ((topo = fopen(file, "r")) == NULL) {
errorBelch("failed to open file '%s'.", file);
return rtsFalse;
}

char line[1000];
char *save, *token, *p;
int r = 0;
nat lines = 0;
int n = 0;
int x;
int procs = getNumberOfProcessors();

unsigned char* temp;
cpu_set_t* set;
size_t size = CPU_ALLOC_SIZE(procs);

temp = (unsigned char*)malloc(size*procs);
if (temp == NULL) {
errorBelch("Failed to allocate cpu set.");
return rtsFalse;
}

while (fgets(line, sizeof(line), topo) != NULL) {
lines++;

cpu_set_t* set = (cpu_set_t*)(temp + (n++ * size));

CPU_ZERO_S(size, set);

for (p = line;; p = NULL) {
token = strtok_r(p, " ", &save);
if (token == NULL)
break;

r = sscanf(token, "0x%x", &x);
if (r != 1)
r = sscanf(token, "%d", &x);

if (r != 1) {
errorBelch("Failed to parse affinity topology line %d char %d: %s\n",
lines, token - line + 1, token);
free(temp);
return rtsFalse;
}

if (x < 0 || x > CPU_SETSIZE) {
errorBelch("CPU given is out of range line %d char %d: %s\n",
lines, token - line + 1, token);
free(temp);
return rtsFalse;
}

CPU_SET_S(x, size, set);
}

if (n >= procs)
break;
}

RtsFlags.ParFlags.setAffinityTopology = realloc(temp, n*size);
RtsFlags.ParFlags.setAffinityTopologySize = size;
RtsFlags.ParFlags.setAffinityTopologyCount = n;

return rtsTrue;
}
#endif

static void GNU_ATTRIBUTE(__noreturn__)
bad_option(const char *s)
{
Expand Down
30 changes: 21 additions & 9 deletions rts/posix/OSThreads.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,28 @@ getNumberOfProcessors (void)
void
setThreadAffinity (nat n, nat m)
{
nat nproc;
cpu_set_t cs;
nat i;

nproc = getNumberOfProcessors();
CPU_ZERO(&cs);
for (i = n; i < nproc; i+=m) {
CPU_SET(i, &cs);
if (RtsFlags.ParFlags.setAffinityTopology != NULL)
{
nat s = RtsFlags.ParFlags.setAffinityTopologySize;
nat c = RtsFlags.ParFlags.setAffinityTopologyCount;
char* p = RtsFlags.ParFlags.setAffinityTopology;

cpu_set_t* set = (cpu_set_t*)(p + (n % c) * s);
sched_setaffinity(0, s, set);
}
else
{
nat nproc;
cpu_set_t cs;
nat i;

nproc = getNumberOfProcessors();
CPU_ZERO(&cs);
for (i = n; i < nproc; i+=m) {
CPU_SET(i, &cs);
}
sched_setaffinity(0, sizeof(cpu_set_t), &cs);
}
sched_setaffinity(0, sizeof(cpu_set_t), &cs);
}

#elif defined(darwin_HOST_OS) && defined(THREAD_AFFINITY_POLICY)
Expand Down

0 comments on commit d50ea1f

Please sign in to comment.