void handleNamedArgumentTable(lua_State* luaSt, const MWNamedArg* args, int table) { const MWNamedArg* p; char buf[128]; int item; p = args; while (p->name) { lua_pushstring(luaSt, p->name); lua_pushvalue(luaSt, -1); /* Copy the key since lua_gettable pops it */ lua_gettable(luaSt, table); item = lua_gettop(luaSt); if (lua_isnil(luaSt, item)) { if (!p->required) { lua_pop(luaSt, 2); ++p; continue; } if (snprintf(buf, sizeof(buf), "Missing required named argument '%s'", p->name) == sizeof(buf)) mw_panic("Error message buffer too small for key name '%s'\n", p->name); luaL_argerror(luaSt, table, buf); } /* We do our own type checking and errors to avoid Confusing and innaccurate error messages, which suggest the use of the table is wrong. */ if (!typeEqualOrConversionOK(luaSt, p->type, -1)) { namedArgumentError(luaSt, p, table, item); } if (p->type == LUA_TUSERDATA) /* We must do another level of checking for the actual type */ { if (!mw_tonamedudata(luaSt, item, p->userDataTypeName)) namedArgumentError(luaSt, p, table, -1); } else if (p->type == LUA_TLIGHTUSERDATA) { mw_panic("Unhandled named argument type lightuserdata\n"); } setValueFromType(luaSt, p, item); lua_pop(luaSt, 2); ++p; } checkExtraArguments(luaSt, args, table); }
static void setValueFromType(lua_State* luaSt, const MWNamedArg* p, int idx) { void* v = p->value; int type = p->type; switch (type) { case LUA_TNUMBER: setNumberFromType(luaSt, p, idx); break; case LUA_TBOOLEAN: *(mwbool*) v = (mwbool) lua_toboolean(luaSt, idx); break; case LUA_TSTRING: *(const char**) v = lua_tostring(luaSt, idx); break; case LUA_TUSERDATA: *(void**) v = lua_touserdata(luaSt, idx); break; case LUA_TTABLE: case LUA_TFUNCTION: case LUA_TLIGHTUSERDATA: case LUA_TTHREAD: case LUA_TNIL: default: mw_panic("Unhandled type %s (%d)\n", luaL_typename(luaSt, type), type); } }
/* TODO: Doesn't clone tree or CL stuffs */ void cloneNBodyState(NBodyState* st, const NBodyState* oldSt) { static const NBodyTree emptyTree = EMPTY_TREE; unsigned int nbody = oldSt->nbody; st->tree = emptyTree; st->tree.rsize = oldSt->tree.rsize; st->freeCell = NULL; st->lastCheckpoint = oldSt->lastCheckpoint; st->step = oldSt->step; st->nbody = oldSt->nbody; st->effNBody = oldSt->effNBody; st->ignoreResponsive = oldSt->ignoreResponsive; st->usesExact = oldSt->usesExact; st->usesQuad = oldSt->usesQuad, st->dirty = oldSt->dirty; st->usesCL = oldSt->usesCL; st->reportProgress = oldSt->reportProgress; st->treeIncest = oldSt->treeIncest; st->tree.structureError = oldSt->tree.structureError; assert(nbody > 0); assert(st->bodytab == NULL && st->acctab == NULL); st->bodytab = (Body*) mwMallocA(nbody * sizeof(Body)); memcpy(st->bodytab, oldSt->bodytab, nbody * sizeof(Body)); st->acctab = (mwvector*) mwMallocA(nbody * sizeof(mwvector)); memcpy(st->acctab, oldSt->acctab, nbody * sizeof(mwvector)); st->orbitTrace = (mwvector*) mwMallocA(N_ORBIT_TRACE_POINTS * sizeof(mwvector)); memcpy(st->orbitTrace, oldSt->orbitTrace, N_ORBIT_TRACE_POINTS * sizeof(mwvector)); if (st->ci) { mw_panic("OpenCL NBodyState cloning not implemented\n"); /* st->ci = (CLInfo*) mwCalloc(1, sizeof(CLInfo)); st->nbb = (NBodyBuffers*) mwCalloc(1, sizeof(NBodyBuffers)); memcpy(st->ci, oldSt->ci, sizeof(CLInfo)); clRetainContext(oldSt->ci->clctx); clRetainProgram(oldSt->ci->prog); clRetainCommandQueue(oldSt->ci->queue); // copy buffers mwDuplicateBuffer(st->ci, oldSt->nbb.blah) */ } }
static scene_t* nbglConnectSharedScene(int instanceId) { int shmId; const int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; struct stat sb; char name[128]; scene_t* scene = NULL; if (snprintf(name, sizeof(name), "/milkyway_nbody_%d", instanceId) == sizeof(name)) { mw_panic("name buffer too small for shared memory name\n"); } shmId = shm_open(name, O_RDWR, mode); if (shmId < 0) { mwPerror("Error getting shared memory"); return NULL; } if (fstat(shmId, &sb) < 0) { mwPerror("shmem fstat"); shm_unlink(name); return NULL; } scene = (scene_t*) mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmId, 0); if (scene == MAP_FAILED) { mwPerror("mmap: Failed to mmap shared memory"); if (shm_unlink(name) < 0) { mwPerror("Unlink shared memory"); } return NULL; } if (sb.st_size < (ssize_t) sizeof(scene_t) || sb.st_size < (ssize_t) nbFindShmemSize(scene->nbody)) { mw_printf("Shared memory segment is impossibly small ("ZU")\n", (size_t) sb.st_size); if (shm_unlink(name) < 0) { mwPerror("Unlink shared memory"); } return NULL; } return scene; }
void* mw_checknamedudata(lua_State* luaSt, int idx, const char* typeName) { void* v; char buf[128]; if (snprintf(buf, sizeof(buf), "`%s' expected", typeName) == sizeof(buf)) mw_panic("Error message buffer too small for expected type name\n"); v = luaL_checkudata(luaSt, idx, typeName); luaL_argcheck(luaSt, v != NULL, idx, buf); return v; }
static EMDDistanceFunction nbMetricDistanceFunction(EMDDistanceType distType) { switch (distType) { case EMD_DIST_L1: return emdDistL1; break; case EMD_DIST_L2: return emdDistL2; break; case EMD_DIST_C: return emdDistC; break; default: mw_panic("Bad or unsupported metric type"); return NULL; } }
static void checkEnumErrorStr(char* errBuf, size_t errBufSize, const MWEnumAssociation* p, const char* badStr) { const MWEnumAssociation* nextP; static const char errStart[] = "Expected enum value where options are: "; char badOpt[1024]; size_t badSize, enumLen, errLen; size_t remSize; /* Remaining size in buffer */ strcpy(errBuf, errStart); errLen = sizeof(errStart) - 1; while (p->enumName) { nextP = &p[1]; enumLen = strlen(p->enumName); if (errLen + enumLen + 6 > errBufSize) /* max possible */ mw_panic("Enum options too large for error string buffer!\n"); errLen += enumLen; if (nextP->enumName) /* If there is a next one, use a comma */ { strcat(strcat(errBuf, p->enumName), ", "); errLen += 2; /* ', ' */ } else { strcat(strcat(strcat(errBuf, "or "), p->enumName), "."); errLen += 4; /* 'or ' + '.' */ } p = nextP; } /* If there's extra space, might as well say what the bad option was */ badSize = snprintf(badOpt, sizeof(badOpt), " Invalid option '%s'", badStr); remSize = sizeof(errBuf) - errLen - 1; if ((badSize != sizeof(badOpt)) && (badSize < remSize)) { strncat(errBuf, badOpt, remSize); } }
/* LUA_TNUMBER can be marshalled to multiple c data types */ static void setNumberFromType(lua_State* luaSt, const MWNamedArg* p, int idx) { const char* userDataTypeName = p->userDataTypeName; void* v = p->value; /* Check if the user specified a numeric type */ if(userDataTypeName) { /* Integer */ if(strcmp(INT_TYPE, userDataTypeName) == 0) { *(int*) v = (int) lua_tonumber(luaSt, idx); return; } /* Unsigned Integer */ if(strcmp(UINT_TYPE, userDataTypeName) == 0) { *(unsigned int*) v = (unsigned int) lua_tonumber(luaSt, idx); return; } /* Double or Float */ if(strcmp(REAL_TYPE, userDataTypeName) == 0) { *(real*) v = (real) lua_tonumber(luaSt, idx); return; } mw_panic("Unknown userDataTypeName (%s) specified in MWNamedArg %s\n", userDataTypeName, p->name); } /* If userDataTypeName is NULL, the default data type is real */ *(real*) v = (real) lua_tonumber(luaSt, idx); return; }
/* Function for sorting bodies */ static int compareBodies(const void* _a, const void* _b) { const Body* a = (const Body*) _a; const Body* b = (const Body*) _b; int rc; char* bufA; char* bufB; if ((rc = compareComponents(Mass(a), Mass(b)))) return rc; /* Masses equal, compare positions */ rc = compareVectors(Pos(a), Pos(b)); if (rc == 0) { bufA = showBody(a); bufB = showBody(b); mw_panic("Comparing bodies with equal positions: %s, %s\n", bufA, bufB); free(bufA); /* Never reached */ free(bufB); } return rc; }
/* Use one of the faster functions if available, or use something forced */ int probabilityFunctionDispatch(const AstronomyParameters* ap, const CLRequest* clr) { int hasSSE2, hasSSE3, hasSSE41, hasAVX; int forcingInstructions = clr->forceAVX || clr->forceSSE41 || clr->forceSSE3 || clr->forceSSE2 || clr->forceX87; int abcd[4]; if (!usingIntrinsicsIsAcceptable(ap, clr->forceNoIntrinsics)) { probabilityFunc = selectStandardFunction(ap); return 0; } mw_cpuid(abcd, 1, 0); hasAVX = mwHasAVX(abcd) && mwOSHasAVXSupport(); hasSSE41 = mwHasSSE41(abcd); hasSSE3 = mwHasSSE3(abcd); hasSSE2 = mwHasSSE2(abcd); if (clr->verbose) { mw_printf("CPU features: SSE2 = %d, SSE3 = %d, SSE4.1 = %d, AVX = %d\n" "Available functions: SSE2 = %d, SSE3 = %d, SSE4.1 = %d, AVX = %d\n" "Forcing: SSE2 = %d, SSE3 = %d, SSE4.1 = %d, AVX = %d\n", hasSSE2, hasSSE3, hasSSE41, hasAVX, initSSE2 != NULL, initSSE3 != NULL, initSSE41 != NULL, initAVX != NULL, clr->forceSSE2, clr->forceSSE3, clr->forceSSE41, clr->forceAVX); } /* If multiple instructions are forced, the highest will take precedence */ if (forcingInstructions) { if (clr->forceAVX && hasAVX && initAVX) { mw_printf("Using AVX path\n"); probabilityFunc = initAVX(); } else if (clr->forceSSE41 && hasSSE41 && initSSE41) { mw_printf("Using SSE4.1 path\n"); probabilityFunc = initSSE41(); } else if (clr->forceSSE3 && hasSSE3 && initSSE3) { mw_printf("Using SSE3 path\n"); probabilityFunc = initSSE3(); } else if (clr->forceSSE2 && hasSSE2 && initSSE2) { mw_printf("Using SSE2 path\n"); probabilityFunc = initSSE2(); } else if (clr->forceX87) { mw_printf("Using other path\n"); probabilityFunc = selectStandardFunction(ap); } else { mw_printf("Tried to force an unusable path\n"); return 1; } } else { /* Choose the highest level with available function and instructions */ if (hasAVX && initAVX) { mw_printf("Using AVX path\n"); probabilityFunc = initAVX(); } else if (hasSSE41 && initSSE41) { mw_printf("Using SSE4.1 path\n"); probabilityFunc = initSSE41(); } else if (hasSSE3 && initSSE3) { mw_printf("Using SSE3 path\n"); probabilityFunc = initSSE3(); } else if (hasSSE2 && initSSE2) { mw_printf("Using SSE2 path\n"); probabilityFunc = initSSE2(); } else { mw_printf("Using other path\n"); probabilityFunc = selectStandardFunction(ap); } } if (!probabilityFunc) { mw_panic("Probability function not set!:\n" " Has AVX = %d\n" " Has SSE4.1 = %d\n" " Has SSE3 = %d\n" " Has SSE2 = %d\n" " Forced AVX = %d\n" " Forced SSE4.1 = %d\n" " Forced SSE3 = %d\n" " Forced SSE2 = %d\n" " Forced x87 = %d\n" " Forced no intrinsics = %d\n" " Arch = %s\n", hasSSE41, hasSSE3, hasSSE2, hasAVX, clr->forceAVX, clr->forceSSE41, clr->forceSSE3, clr->forceSSE2, clr->forceX87, clr->forceNoIntrinsics, ARCH_STRING); } return 0; }
/* Use one of the faster functions if available */ static void probabilityFunctionDispatch(const AstronomyParameters* ap, const CLRequest* clr) { int hasSSE2 = FALSE, hasSSE3 = FALSE; int useSSE2 = FALSE, useSSE3 = FALSE; getSSELevelSupport(&hasSSE2, &hasSSE3); if (clr->verbose) { warn("CPU features: SSE2 = %d, SSE3 = %d\n" "Forcing: SSE2 = %d, SSE3 = %d, x87 = %d\n", hasSSE2, hasSSE3, clr->forceSSE2, clr->forceSSE3, clr->forceX87); } if (!clr->forceSSE2 && !clr->forceSSE3 && !clr->forceX87) { /* Default to using highest capability if not forcing anything */ useSSE3 = hasSSE3; useSSE2 = hasSSE2; } else if (clr->forceSSE2) { useSSE2 = TRUE; } else if (clr->forceSSE3) { useSSE3 = TRUE; } else if (clr->forceX87) { #if MW_IS_X86_32 useSSE2 = useSSE3 = FALSE; #elif MW_IS_X86_64 useSSE2 = TRUE; /* Ignore flag */ #endif } if (useSSE3) /* Precedence to higher level */ { warn("Using SSE3 path\n"); probabilityFunc = initProbabilities_SSE3(ap, clr->forceNoIntrinsics); } else if (useSSE2) { warn("Using SSE2 path\n"); probabilityFunc = initProbabilities_SSE2(ap, clr->forceNoIntrinsics); } else { #if !MW_NO_X87_EVER warn("Using x87 path\n"); probabilityFunc = initProbabilities(ap, clr->forceNoIntrinsics); #else mw_unreachable(); #endif } if (!probabilityFunc) { mw_panic("Probability function not set!:\n" " Has SSE2 = %d\n" " Has SSE3 = %d\n" " Forced SSE3 = %d\n" " Forced SSE2 = %d\n" " Forced x87 = %d\n" " Forced no intrinsics = %d\n" " Arch = %s\n", hasSSE2, hasSSE3, clr->forceSSE3, clr->forceSSE2, clr->forceX87, clr->forceNoIntrinsics, ARCH_STRING); } }
/* Create the next available segment of the form /milkyway_nbody_n n = 0 .. 127*/ int nbCreateSharedScene(NBodyState* st, const NBodyCtx* ctx) { size_t size = sizeof(scene_t) + st->nbody * sizeof(FloatPos); int shmId = -1; const int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; void* p = NULL; int instanceId = -1; char name[128]; /* Try looking for the next available segment of the form /milkyway_nbody_<n> */ while (shmId < 0 && instanceId < MAX_INSTANCES) { ++instanceId; if (snprintf(name, sizeof(name), "/milkyway_nbody_%d", instanceId) == sizeof(name)) mw_panic("Buffer too small for scared memory name\n"); shmId = shm_open(name, O_CREAT | O_RDWR | O_EXCL, mode); /* Try to open exclusively */ if (shmId < 0 && errno != EEXIST) /* Only failed if */ { mwPerror("Error creating shared memory '%s'", name); return 1; } } if (instanceId >= MAX_INSTANCES) { mw_printf("Could not open new shm segment in %d tries\n", MAX_INSTANCES); return 1; } if (ftruncate(shmId, size) < 0) /* Make the segment the correct size */ { mwPerror("Error ftruncate() shared memory"); if (shm_unlink(name) < 0) { mwPerror("Error unlinking shared memory '%s'", name); } return 1; } p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmId, 0); if (p == MAP_FAILED) { mwPerror("mmap: Failed to mmap shared memory"); if (shm_unlink(name) < 0) { mwPerror("Error unlinking shared memory '%s'", name); } return 1; } st->scene = (scene_t*) p; st->shmId = shmId; st->scene->instanceId = instanceId; strncpy(st->scene->shmemName, name, sizeof(st->scene->shmemName)); nbPrepareSceneFromState(ctx, st); return 0; }
void nbLaunchVisualizer(NBodyState* st, const char* visArgs) { pid_t pid; const char* path = NULL; char* newPath = NULL; int argc = 0; char* buf = NULL; char* p = NULL; char** argv = NULL; size_t argvSize = 0; size_t visArgsLen = 0; char idArg[128]; if (!st->scene) /* If there's no scene to share, there's no point */ return; if (st->usesExact) { mw_printf("Visualizer broken with Exact\n"); return; } pid = fork(); if (pid != 0) /* Parent */ return; /* Child */ /* Put places convenient for testing. Not essential, failure of * any of these is OK */ path = getenv("PATH"); if (!path) { mwPerror("Error getting PATH"); } else { if (asprintf(&newPath, ".:../bin/:%s", path) < 0) { mwPerror("Appending to path"); } else { if (setenv("PATH", newPath, TRUE) < 0) { mwPerror("Error setting PATH"); } free(newPath); } } if (snprintf(idArg, sizeof(idArg), "--instance-id=%d ", st->scene->instanceId) == sizeof(idArg)) mw_panic("Buffer too small for --instance-id visualizer argument\n"); /* Stick the program name at the head of the arguments passed in */ visArgsLen = visArgs ? strlen(visArgs) : 0; argvSize = visArgsLen + sizeof(idArg) + sizeof(nbodyGraphicsName) + 2; /* arguments + program name + space + null */ buf = mwCalloc(argvSize, sizeof(char)); p = stpcpy(buf, nbodyGraphicsName); p = stpcpy(p, " "); p = stpcpy(p, idArg); if (visArgs) { stpcpy(p, visArgs); } if (poptParseArgvString(buf, &argc, (const char***) &argv)) { mw_printf("Error parsing arguments for visualizer '%s'\n", visArgs); free(buf); return; } if (execvp(argv[0], argv) < 0) { mwPerror("Failed to launch visualizer '%s'", argv[0]); } free(buf); free(argv); mw_finish(EXIT_SUCCESS); /* Unnecessary */ }