/** * \brief Returns the ID of the CPU * * It returns the ID of the CPU where the calling thread is running. It works * on Linux OS and Apple OS. * * \return An integer value showing the ID of the core. If the ID of the core * is not found, then -1 is returned. */ static inline int ff_getMyCpu() { #if defined(__linux__) && defined(CPU_SET) cpu_set_t mask; CPU_ZERO(&mask); if (sched_getaffinity(gettid(), sizeof(mask), &mask) != 0) { perror("sched_getaffinity"); return EINVAL; } for(int i=0;i<CPU_SETSIZE;++i) if (CPU_ISSET(i,&mask)) return i; #elif defined(__APPLE__) && MAC_OS_X_HAS_AFFINITY // Not tested struct thread_affinity_policy mypolicy; boolean_t get_default; mach_msg_type_number_t thread_info_count = THREAD_AFFINITY_POLICY_COUNT; thread_policy_get(mach_thread_self(), THREAD_AFFINITY_POLICY, (integer_t*) &mypolicy, &thread_info_count, &get_default); int res = mypolicy.affinity_tag; return(res); #else #if __GNUC__ #warning "ff_getMyCpu not supported" #else std::cerr << "---> ff_getMyCpu not supported\n"; #pragma message( "ff_getMyCpu not supported") #endif #endif return -1; }
static void get_affinity(pthread_t thread) { thread_affinity_policy theTCPolicy; mach_msg_type_number_t count = THREAD_AFFINITY_POLICY_COUNT; boolean_t get_default = false; kern_return_t res = thread_policy_get(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (thread_policy_t)&theTCPolicy, &count, &get_default); if (res == KERN_SUCCESS) { //printf("get_affinity = %d\n", theTCPolicy.affinity_tag); } }
//Polls a (non-realtime) thread to find out how it is scheduled //Results are undefined of an error is returned. Otherwise, the //priority is returned in the address pointed to by the priority //parameter, and whether or not the thread uses timeshare scheduling //is returned at the address pointed to by the isTimeShare parameter kern_return_t GetStdThreadSchedule( mach_port_t machThread, int *priority, boolean_t *isTimeshare ) { kern_return_t result = 0; thread_extended_policy_data_t timeShareData; thread_precedence_policy_data_t precedenceData; mach_msg_type_number_t structItemCount; boolean_t fetchDefaults = false; memset( &timeShareData, 0, sizeof( thread_extended_policy_data_t )); memset( &precedenceData, 0, sizeof( thread_precedence_policy_data_t )); if( 0 == machThread ) machThread = mach_thread_self(); if( NULL != isTimeshare ) { structItemCount = THREAD_EXTENDED_POLICY_COUNT; result = thread_policy_get( machThread, THREAD_EXTENDED_POLICY, (integer_t*)&timeShareData, &structItemCount, &fetchDefaults ); *isTimeshare = timeShareData.timeshare; if( 0 != result ) return result; } if( NULL != priority ) { fetchDefaults = false; structItemCount = THREAD_PRECEDENCE_POLICY_COUNT; result = thread_policy_get( machThread, THREAD_PRECEDENCE_POLICY, (integer_t*)&precedenceData, &structItemCount, &fetchDefaults ); *priority = precedenceData.importance; } return result; }
int pthread_getaffinity(pthread_t thread, unsigned int *core) { /* Convert pthread ID */ mach_port_t mach_thread = pthread_mach_thread_np(thread); thread_affinity_policy_data_t policy; mach_msg_type_number_t count = THREAD_AFFINITY_POLICY_COUNT; boolean_t get_default = FALSE; kern_return_t rc = thread_policy_get(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t) &policy, &count, &get_default); *core = (unsigned int)policy.affinity_tag; return (rc == KERN_SUCCESS ? 0 : -1); }
int thread_tag_get(thread_t thread) { kern_return_t ret; boolean_t get_default = FALSE; thread_affinity_policy_data_t policy; mach_msg_type_number_t count = THREAD_AFFINITY_POLICY_COUNT; ret = thread_policy_get( thread, THREAD_AFFINITY_POLICY, (thread_policy_t) &policy, &count, &get_default); if (ret != KERN_SUCCESS) { printf("thread_policy_set(1) returned %d\n", ret); exit(1); } return policy.affinity_tag; }
static int GetParams(pthread_t thread, UInt64* period, UInt64* computation, UInt64* constraint) { thread_time_constraint_policy_data_t theTCPolicy; mach_msg_type_number_t count = THREAD_TIME_CONSTRAINT_POLICY_COUNT; boolean_t get_default = false; kern_return_t res = thread_policy_get(pthread_mach_thread_np(thread), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) & theTCPolicy, &count, &get_default); if (res == KERN_SUCCESS) { *period = AudioConvertHostTimeToNanos(theTCPolicy.period); *computation = AudioConvertHostTimeToNanos(theTCPolicy.computation); *constraint = AudioConvertHostTimeToNanos(theTCPolicy.constraint); return 0; } else { return -1; } }
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { bool isError; thread_policy_flavor_t flavorConstant; int flavorPolicySize, flavorPolicySizeBytes, kernError; task_t threadID; thread_policy_t threadPolicy; mach_msg_type_number_t policySizeFilled; boolean_t isDefault, getDefault; char commandString[COMMAND_STRING_LENGTH]; // for return structure // ...outer const char *outerNames[] = {"threadID", "flavor", "policy", "policySize", "policyFillSize", "getDefault", "isDefault"}; int numOuterDims=2, numOuterFields=7; int outerDims[2]={1,1}; // ...inner const char *standardNames[] = {"no_data"}; int numInnerFieldsStandard= 1; /* const char *extendedNames[] = {"timeshare"}; int numInnerFieldsExtended= 1; */ const char *timeConstraintNames[]= {"period", "computation", "constraint", "preemptible"}; int numInnerFieldsTimeConstraint= 4; const char *precedenceNames[]= {"imporantance"}; int numInnerFieldsPrecedence= 1; int numInnerDims=2; int innerDims[2]={1,1}; // ...both mxArray *tempFieldValue, *innerStruct, *outerStruct; //get the policy flavor constant specified by the user and the getDefault argument if(nrhs<2 || nrhs > 2) mexErrMsgTxt("MachGetPriorityMex requires two input arguments. See help MachGetPriorityMex."); if(!mxIsChar(prhs[0])) mexErrMsgTxt("First input argument is not a string. See help MachGetPriorityMex."); mxGetString(prhs[0], commandString, COMMAND_STRING_LENGTH); isError=GetFlavorConstantFromFlavorString(commandString, mxGetM(prhs[0]) * mxGetN(prhs[0]), &flavorConstant); //case sensitive. if(isError) mexErrMsgTxt("Unrecognized command. See help MachGetPriorityMex."); if(!(mxIsDouble(prhs[1]) || mxIsLogical(prhs[1])) || mxGetN(prhs[1]) * mxGetM(prhs[1]) != 1) mexErrMsgTxt("Second argument must be 1x1 logical or double value. See help MachGetPriorityMex."); if(mxIsLogical(prhs[1])) getDefault= (boolean_t)mxGetLogicals(prhs[1])[0]; if(mxIsDouble(prhs[1])) getDefault= (boolean_t)mxGetPr(prhs[1])[0]; //read the priority settings switch(flavorConstant){ case THREAD_STANDARD_POLICY: flavorPolicySizeBytes=sizeof(thread_standard_policy_data_t); flavorPolicySize=THREAD_STANDARD_POLICY_COUNT; break; case THREAD_TIME_CONSTRAINT_POLICY: flavorPolicySizeBytes=sizeof(thread_time_constraint_policy_data_t); flavorPolicySize=THREAD_TIME_CONSTRAINT_POLICY_COUNT; break; case THREAD_PRECEDENCE_POLICY: flavorPolicySizeBytes=sizeof(thread_precedence_policy_data_t); flavorPolicySize=THREAD_PRECEDENCE_POLICY_COUNT; break; } threadPolicy=(thread_policy_t)malloc(flavorPolicySizeBytes); threadID= mach_thread_self(); policySizeFilled=flavorPolicySize; isDefault=getDefault; kernError=thread_policy_get(threadID, flavorConstant, threadPolicy, &policySizeFilled, &isDefault); //create and populate the return structure outerStruct= mxCreateStructArray(numOuterDims, outerDims, numOuterFields, outerNames); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]=(double)threadID; mxSetField(outerStruct, 0, "threadID", tempFieldValue); tempFieldValue= mxCreateString(commandString); mxSetField(outerStruct, 0, "flavor", tempFieldValue); switch(flavorConstant){ case THREAD_STANDARD_POLICY: innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsStandard, standardNames); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_standard_policy_t)threadPolicy)->no_data; mxSetField(innerStruct, 0, "no_data", tempFieldValue); break; /* THREAD_EXTENDED_POLICY is equal to THREAD_STANDARD_POLICY. Also, THREAD_EXTENDED_POLICY is undocumented. So we ignore it. case THREAD_EXTENDED_POLICY: innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsExtended, extendedNames); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_extended_policy_t)threadPolicy)->timeshare; mxSetField(innerStruct, 1, "timeshare", tempFieldValue); break; */ case THREAD_TIME_CONSTRAINT_POLICY: innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsTimeConstraint, timeConstraintNames); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->period; mxSetField(innerStruct, 0, "period", tempFieldValue); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->computation; mxSetField(innerStruct, 0, "computation", tempFieldValue); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->constraint; mxSetField(innerStruct, 0, "constraint", tempFieldValue); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_time_constraint_policy_t)threadPolicy)->preemptible; mxSetField(innerStruct, 0, "preemptible", tempFieldValue); break; case THREAD_PRECEDENCE_POLICY: innerStruct= mxCreateStructArray(numInnerDims, innerDims, numInnerFieldsPrecedence, precedenceNames); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]= (double)((thread_precedence_policy_t)threadPolicy)->importance; mxSetField(innerStruct, 0, "imporantance", tempFieldValue); break; } mxSetField(outerStruct,0, "policy", innerStruct); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]=flavorPolicySize; mxSetField(outerStruct, 0, "policySize", tempFieldValue); tempFieldValue= mxCreateDoubleMatrix(1,1,mxREAL); mxGetPr(tempFieldValue)[0]=policySizeFilled; mxSetField(outerStruct, 0, "policyFillSize", tempFieldValue); tempFieldValue= mxCreateLogicalMatrix(1, 1); mxGetLogicals(tempFieldValue)[0]=(bool)getDefault; mxSetField(outerStruct, 0, "getDefault", tempFieldValue); tempFieldValue= mxCreateLogicalMatrix(1, 1); mxGetLogicals(tempFieldValue)[0]=(bool)isDefault; mxSetField(outerStruct, 0, "isDefault", tempFieldValue); plhs[0]=outerStruct; free((void*)threadPolicy); }
/* Change priority for thread 'threadhandle', or for the calling thread if 'threadhandle' == NULL. * threadhandle == 0x1 means "Main Psychtoolbox thread" and may incur special treatment. * 'basePriority' can be 0 for normal scheduling, 1 for higher priority and 2 for highest priority. * 'tweakPriority' modulates more fine-grained within the category given by 'basepriority'. It * can be anywhere between 0 and some big value where bigger means more priority. * * Returns zero on success, non-zero on failure to set new priority. */ int PsychSetThreadPriority(psych_thread* threadhandle, int basePriority, int tweakPriority) { int rc = 0; pthread_t thread; int kernError; task_t threadID; thread_policy_t threadPolicy; mach_msg_type_number_t policyCount, policyCountFilled; boolean_t isDefault; if ((NULL != threadhandle) && ((psych_thread*) 0x1 != threadhandle)) { // Retrieve thread handle of thread to change: thread = *threadhandle; } else { // Retrieve handle of calling thread: thread = pthread_self(); } // Map Posix thread handle to Mach thread handle: threadID = pthread_mach_thread_np(thread); // Get timebase: double ticksPerSec = PsychGetKernelTimebaseFrequencyHz(); double baseQuantum = 0.010; // tweakPriority <= 0 -> 10% cpu. Can go up to 90% at level >=8 in 10% increments. if (tweakPriority < 0) tweakPriority = 0; if (tweakPriority > 8) tweakPriority = 8; switch(basePriority) { case 0: // Normal priority: Drop to standard scheduling. threadPolicy = (thread_policy_t) malloc(sizeof(thread_standard_policy_data_t)); policyCount = THREAD_STANDARD_POLICY_COUNT; policyCountFilled = policyCount; isDefault = TRUE; kernError = thread_policy_get(threadID, THREAD_STANDARD_POLICY, threadPolicy, &policyCountFilled, &isDefault); if (kernError == 0) kernError = thread_policy_set(threadID, THREAD_STANDARD_POLICY, threadPolicy, policyCountFilled); free(threadPolicy); rc = (int) kernError; break; case 1: // High priority: Up to 90% cpu utilization, but preemptible for urgent tasks, with an allowable total time to completion of baseQuantum. // This basically says: "I am more important than bog-standard threads, and i want to have x msecs of 10 msecs very 10 msecs, but i don't care // about startup delay (reaction times) or interruptions, as long as i don't lose more than 10 msecs. Good for high priority compute tasks // with lots of wiggle room wrt. when stuff happens, e.g., some data producer thread or i/o thread which needs to deliver/handle a certain // amount of data processing/shuffling/io within a certain time quantum, because it is feeding some other realtime thread or hw process, // due to things like intermediate fifo buffering, itself can tolerate a certain lag. // This may become useful in the future for i/o functions in IOPort/PsychHID, movie playback/recording helper threads etc... rc = set_realtime(threadID, baseQuantum * ticksPerSec, (((double) tweakPriority + 1) / 10) * baseQuantum * ticksPerSec, baseQuantum * ticksPerSec, TRUE); break; case 2: // Realtime priority: Up to (tweakPriority + 1) msecs out of 10 msecs of *uninterrupted* computation (non-preemptible after start). // However, after the thread becomes runnable, its actual start of uninterrupted execution can be delayed by up to 1 msec, e.g., if more // important (basePriority 10) threads are executing, or a high priority or lower priority thread needs some computation time. // This is our most common use-case: Most of our realtime threads are completely triggered (= reactive to) by external hardware input events. // They wait on the arrival of some external event, e.g., a user key press or mouse click, some trigger signal from some I/O device like // response box, serial port or parallel port, DAQ board etc., or for some timer going off at a certain time. Most often they have to respond // to some trigger event by either executing some action, or by simply timestamping the event, like a button press of a subject, or some TTL // trigger from some equipment. Executing the actual action, or timestamping, or storing the received data in some queue, is usually fast, // the computation finishes quickly. As timestamping or external hardware control can be involved, we don't want to get preempted once running, // to avoid impairing precision of timestamps or clock-sync algorithms or hw control actions. However for typical neuro-science experiments, // we can tolerate a random time delay (or imprecision in acquired timestamps) of 1 msec. // Typical consumers of this setup: IOPort, PsychHID, Movie playback or video capture high-level control. rc = set_realtime(threadID, baseQuantum * ticksPerSec, (((double) tweakPriority + 1) / 10) * baseQuantum * ticksPerSec, (((double) tweakPriority + 1 + 1) / 10) * baseQuantum * ticksPerSec, FALSE); break; case 10: // Critical priority: Up to (tweakPriority + 1) msecs out of 10 msecs of *uninterrupted* computation (non-preemptible after start), // must run as soon as possible and then complete without distraction. This is good for timestamping operations that must not be interrupted // in the wrong moment, because that would impair timestamps significantly, and for time-based triggering of execution of operations with // the highest possible timing precision. // Out main client of this is currently the OpenGL flipperThread used by Screen for async flip scheduling and timestamping, and for // frame-sequential stereo fallback. For those apps, uninterrupted low latency is crucial. flipperThread uses tweakPriority == 2, so could // run for up to 3 msecs uninterrupted, something it usually won't do (closer to << 1 msec is expected), but can do in a worst case scenario, // where various workarounds for broken GPU drivers are active and screen resolution/refresh rate settings are especially suboptimal. // The other client is video refresh rate calibration during Screen('GetFlipInterval') active calibration or during Screen('Openwindow') // default calibration. // // Future clients may be found in the IOPort async-task framework for highly timing sensitive i/o operations. rc = set_realtime(threadID, baseQuantum * ticksPerSec, (((double) tweakPriority + 1) / 10) * baseQuantum * ticksPerSec, 0, FALSE); break; default: printf("PTB-CRITICAL: In call to PsychSetThreadPriority(): Invalid/Unknown basePriority %i provided!\n", basePriority); rc = 2; } // Try to apply new priority and scheduling method: if (rc != 0) { printf("PTB-WARNING: In call to PsychSetThreadPriority(): Failed to set new basePriority %i, tweakPriority %i, effective %i [%s] for thread %p provided!\n", basePriority, tweakPriority, tweakPriority, (basePriority > 0) ? "REALTIME" : "NORMAL", (void*) threadhandle); printf("PTB-WARNING: This can lead to timing glitches and odd performance behaviour.\n"); } // rc is either zero for success, or 2 for invalid arg, or some other non-zero failure code: return(rc); }
PsychError MACHPRIORITYMachPriority(void) { //double *returnValue; //int newPriority; const char *outerStructFieldNames[]={"thread", "flavor", "policy"}; const char *policyStructFieldNames[]={"period", "computation", "constraint", "preemptible"}; int numOuterStructDimensions=1, numOuterStructFieldNames=3, numPolicyStructDimensions=1, numPolicyStructFieldNames=4; PsychGenericScriptType *outerStructArray, *policyStructArray; int kernError, numInputArgs; thread_act_t threadID; static thread_policy_flavor_t currentThreadFlavor=THREAD_STANDARD_POLICY; struct thread_time_constraint_policy oldPolicyInfo, newPolicyInfo; mach_msg_type_number_t msgTypeNumber; boolean_t getDefault; char *flavorStr; boolean setNewMode; double *periodArg, *computationArg, *constraintArg, *preemptibleArg; char errorMessageStr[256]; //check to see if the user supplied superfluous arguments PsychErrorExit(PsychCapNumOutputArgs(1)); PsychErrorExit(PsychCapNumInputArgs(4)); //actually we permit only zero or three arguments. numInputArgs=PsychGetNumInputArgs(); if(numInputArgs==4) setNewMode=TRUE; else if(numInputArgs==0) setNewMode=FALSE; else PsychErrorExitMsg(PsychError_user,"Incorrect number of arguments. Either zero or four arguments accepted"); //read the current settings threadID= mach_thread_self(); currentThreadFlavor=THREAD_TIME_CONSTRAINT_POLICY; msgTypeNumber=THREAD_TIME_CONSTRAINT_POLICY_COUNT; getDefault=FALSE; kernError= thread_policy_get(threadID, currentThreadFlavor, (int *)&oldPolicyInfo, &msgTypeNumber, &getDefault); if(kernError != KERN_SUCCESS) PsychErrorExitMsg(PsychError_internal,"\"thread_policy_get()\" returned and error when reading current thread policy"); //fill in the outgoig struct with current thread settings values. //outer struct PsychAllocOutStructArray(1, FALSE, numOuterStructDimensions, numOuterStructFieldNames, outerStructFieldNames, &outerStructArray); PsychSetStructArrayDoubleElement("thread", 0, (double)threadID, outerStructArray); flavorStr=GetFlavorStringFromFlavorConstant(currentThreadFlavor); PsychSetStructArrayStringElement("flavor", 0, flavorStr, outerStructArray); //enclosed policy struct PsychAllocOutStructArray(-1, FALSE, numPolicyStructDimensions, numPolicyStructFieldNames, policyStructFieldNames, &policyStructArray); PsychSetStructArrayDoubleElement("period", 0, (double)oldPolicyInfo.period, policyStructArray); PsychSetStructArrayDoubleElement("computation", 0, (double)oldPolicyInfo.computation, policyStructArray); PsychSetStructArrayDoubleElement("constraint", 0, (double)oldPolicyInfo.constraint, policyStructArray); PsychSetStructArrayDoubleElement("preemptible", 0, (double)oldPolicyInfo.preemptible, policyStructArray); PsychSetStructArrayStructElement("policy",0, policyStructArray, outerStructArray); //Set the priority if(setNewMode){ //if there is only one argument then it must be the flavor argument re PsychAllocInDoubleArg(1, TRUE, &periodArg); PsychAllocInDoubleArg(2, TRUE, &computationArg); PsychAllocInDoubleArg(3, TRUE, &constraintArg); PsychAllocInDoubleArg(4, TRUE, &preemptibleArg); newPolicyInfo.period=(uint32_t)*periodArg; newPolicyInfo.computation=(uint32_t)*computationArg; newPolicyInfo.constraint=(uint32_t)*constraintArg; newPolicyInfo.preemptible=(boolean_t)*preemptibleArg; kernError= thread_policy_set(threadID, THREAD_TIME_CONSTRAINT_POLICY, (int *)&newPolicyInfo, THREAD_TIME_CONSTRAINT_POLICY_COUNT); if(kernError != KERN_SUCCESS){ sprintf(errorMessageStr,"%s%d", "\"thread_policy_set()\" returned and error when setting new thread policy: ", (int)kernError); PsychErrorExitMsg(PsychError_internal, errorMessageStr); } } return(PsychError_none); }
static void thread_print_policies(int fDefault) { thread_extended_policy_data_t Extended = { 0 }; thread_time_constraint_policy_data_t TimeConstraint = { 0, 0, 0, 1 }; thread_precedence_policy_data_t Precedence = { 0 }; #ifdef THREAD_AFFINITY_POLICY /* 10.5 */ thread_affinity_policy_data_t Affinity = { 0 }; #endif boolean_t GetDefault; mach_msg_type_number_t Count; kern_return_t krc; GetDefault = fDefault; Count = THREAD_EXTENDED_POLICY_COUNT; krc = thread_policy_get(mach_thread_self(), THREAD_EXTENDED_POLICY, (thread_policy_t)&Extended, &Count, &GetDefault); printf("THREAD_EXTENDED_POLICY: krc=%#x default=%d timeshare=%d (%#x)\n", krc, GetDefault, Extended.timeshare, Extended.timeshare); GetDefault = fDefault; Count = THREAD_PRECEDENCE_POLICY_COUNT; krc = thread_policy_get(mach_thread_self(), THREAD_PRECEDENCE_POLICY, (thread_policy_t)&Precedence, &Count, &GetDefault); printf("THREAD_PRECEDENCE_POLICY: krc=%#x default=%d importance=%d (%#x)\n", krc, GetDefault, Precedence.importance, Precedence.importance); GetDefault = fDefault; Count = THREAD_TIME_CONSTRAINT_POLICY_COUNT; krc = thread_policy_get(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&TimeConstraint, &Count, &GetDefault); printf("THREAD_TIME_CONSTRAINT_POLICY: krc=%#x default=%d period=%u (%#x) computation=%u (%#x) constraint=%u (%#x) preemptible=%d\n", krc, GetDefault, TimeConstraint.period, TimeConstraint.period, TimeConstraint.computation, TimeConstraint.computation, TimeConstraint.constraint, TimeConstraint.constraint, TimeConstraint.preemptible); #ifdef THREAD_AFFINITY_POLICY /* 10.5 */ GetDefault = fDefault; Count = THREAD_AFFINITY_POLICY_COUNT; krc = thread_policy_get(mach_thread_self(), THREAD_AFFINITY_POLICY, (thread_policy_t)&Affinity, &Count, &GetDefault); printf("THREAD_AFFINITY_POLICY: krc=%#x default=%d affinity_tag=%d (%#x)\n", krc, GetDefault, Affinity.affinity_tag, Affinity.affinity_tag); #endif if (!fDefault) { struct sched_param Param; int iPolicy = 0; struct thread_basic_info BasicInfo = {{0,0},{0,0},0,0,0,0,0,0}; struct policy_timeshare_info TSInfo = {0,0,0,0,0}; int rc; int i; memset(&Param, 0, sizeof(Param)); rc = pthread_getschedparam(pthread_self(), &iPolicy, &Param); printf("pthread_getschedparam: rc=%d iPolicy=%d (%#x) sched_priority=%d (%#x) opaque=%d (%#x)\n", rc, iPolicy, iPolicy, Param.sched_priority, Param.sched_priority, #ifdef THREAD_AFFINITY_POLICY /* 10.5 */ *(int *)&Param.__opaque, *(int *)&Param.__opaque); #else *(int *)&Param.opaque, *(int *)&Param.opaque); #endif Count = THREAD_BASIC_INFO_COUNT; krc = thread_info(mach_thread_self(), THREAD_BASIC_INFO, (thread_info_t)&BasicInfo, &Count); printf("THREAD_BASIC_INFO: krc=%#x user_time=%d.%06d system_time=%d.%06d cpu_usage=%d policy=%d\n" " run_state=%d flags=%#x suspend_count=%d sleep_time=%d\n", krc, BasicInfo.user_time.seconds, BasicInfo.user_time.microseconds, BasicInfo.system_time.seconds, BasicInfo.system_time.microseconds, BasicInfo.cpu_usage, BasicInfo.policy, BasicInfo.run_state, BasicInfo.flags, BasicInfo.suspend_count, BasicInfo.sleep_time); Count = POLICY_TIMESHARE_INFO_COUNT; krc = thread_info(mach_thread_self(), THREAD_SCHED_TIMESHARE_INFO, (thread_info_t)&TSInfo, &Count); printf("THREAD_SCHED_TIMESHARE_INFO: krc=%#x max_priority=%d (%#x) base_priority=%d (%#x) cur_priority=%d (%#x)\n" " depressed=%d depress_priority=%d (%#x)\n", krc, TSInfo.max_priority, TSInfo.max_priority, TSInfo.base_priority, TSInfo.base_priority, TSInfo.cur_priority, TSInfo.cur_priority, TSInfo.depressed, TSInfo.depress_priority, TSInfo.depress_priority); } else {
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { bool isError; thread_policy_flavor_t flavorConstant; int kernError; task_t threadID; thread_policy_t threadPolicy; mach_msg_type_number_t policyCount, policyCountFilled; boolean_t isDefault; char commandString[COMMAND_STRING_LENGTH]; threadID= mach_thread_self(); kernError=0; //get the policy flavor constant specified by the user and the getDefault argument if(nrhs<1) mexErrMsgTxt("MachGetPriorityMex requires at least one argument. See help MachGetPriorityMex."); if(!mxIsChar(prhs[0])) mexErrMsgTxt("First input argument is not a string. See help MachGetPriorityMex."); mxGetString(prhs[0], commandString, COMMAND_STRING_LENGTH); isError=GetFlavorConstantFromFlavorString(commandString, mxGetM(prhs[0]) * mxGetN(prhs[0]), &flavorConstant); //case sensitive. if(isError) mexErrMsgTxt("Unrecognized command. See help MachGetPriorityMex."); //branch according to the first argument switch(flavorConstant){ case THREAD_STANDARD_POLICY: if(nrhs>2) mexErrMsgTxt("Extra argument(s) detected. See help MachGetPriorityMex."); if(nrhs==2){ if(!mxIsChar(prhs[1])) mexErrMsgTxt("Expecting string in second argument. See help MachGetPriorityMex."); mxGetString(prhs[1], commandString, COMMAND_STRING_LENGTH); commandString[COMMAND_STRING_LENGTH-1]= '\0'; //guarantee strcmp an end of string character if(strcmp(commandString, "default")) mexErrMsgTxt("Unrecognized second argument. See help MachGetPriorityMex."); } threadPolicy=(thread_policy_t)malloc(sizeof(thread_standard_policy_data_t)); policyCount=THREAD_STANDARD_POLICY_COUNT; policyCountFilled=policyCount; isDefault=TRUE; kernError=thread_policy_get(threadID, THREAD_STANDARD_POLICY, threadPolicy, &policyCountFilled, &isDefault); if (kernError==0) kernError=thread_policy_set(threadID, THREAD_STANDARD_POLICY, threadPolicy, policyCountFilled); break; case THREAD_TIME_CONSTRAINT_POLICY: if(nrhs==1) mexErrMsgTxt("Missing argument detected. See help MachGetPriorityMex."); else if(nrhs==2){ if(!mxIsChar(prhs[1])) mexErrMsgTxt("Expecting string in second argument. See help MachGetPriorityMex."); mxGetString(prhs[1], commandString, COMMAND_STRING_LENGTH); commandString[COMMAND_STRING_LENGTH-1]= '\0'; //guarantee strcmp an end of string character if(strcmp(commandString, "default")) mexErrMsgTxt("Unrecognized second argument. See help MachGetPriorityMex."); threadPolicy=(thread_policy_t)malloc(sizeof(thread_time_constraint_policy_data_t)); policyCount=THREAD_TIME_CONSTRAINT_POLICY_COUNT; policyCountFilled=policyCount; isDefault=TRUE; kernError=thread_policy_get(threadID, THREAD_TIME_CONSTRAINT_POLICY, threadPolicy, &policyCountFilled, &isDefault); if (kernError==0) kernError=thread_policy_set(threadID, THREAD_TIME_CONSTRAINT_POLICY, threadPolicy, policyCountFilled); free((void*)threadPolicy); break; }else if(nrhs != 5) mexErrMsgTxt("Incorrect number of arguments. See help MachGetPriorityMex."); else{ if(! (mxIsDouble(prhs[1]) && mxGetM(prhs[1]) * mxGetN(prhs[1]) == 1)) mexErrMsgTxt("Expected double in second argument. See help MachSetPriorityMex."); if(! (mxIsDouble(prhs[2]) && mxGetM(prhs[2]) * mxGetN(prhs[2]) == 1)) mexErrMsgTxt("Expected double in third argument. See help MachSetPriorityMex."); if(! (mxIsDouble(prhs[3]) && mxGetM(prhs[3]) * mxGetN(prhs[3]) == 1)) mexErrMsgTxt("Expected double in fourth argument. See help MachGetPriorityMex."); if(!((mxIsDouble(prhs[4]) || mxIsLogical(prhs[4])) && (mxGetM(prhs[4]) * mxGetN(prhs[4]) == 1))) mexErrMsgTxt("Expected double or logical in fifth argument. See help MachSetPriorityMex."); threadPolicy=(thread_policy_t)malloc(sizeof(thread_time_constraint_policy_data_t)); ((thread_time_constraint_policy_t)threadPolicy)->period=(uint32_t)mxGetPr(prhs[1])[0]; ((thread_time_constraint_policy_t)threadPolicy)->computation=(uint32_t)mxGetPr(prhs[2])[0]; ((thread_time_constraint_policy_t)threadPolicy)->constraint=(uint32_t)mxGetPr(prhs[3])[0]; ((thread_time_constraint_policy_t)threadPolicy)->preemptible= (boolean_t)(mxIsDouble(prhs[4]) ? mxGetPr(prhs[4])[0] : mxGetLogicals(prhs[4])[0]); policyCount=THREAD_TIME_CONSTRAINT_POLICY_COUNT; policyCountFilled=policyCount; kernError=thread_policy_set(threadID, THREAD_TIME_CONSTRAINT_POLICY, threadPolicy, policyCountFilled); free((void*)threadPolicy); break; } case THREAD_PRECEDENCE_POLICY: if(nrhs>2) mexErrMsgTxt("Extra argument(s) detected. See help MachGetPriorityMex."); if(nrhs<2) mexErrMsgTxt("Missing argument detected. See help MachGetPriorityMex."); if(mxIsChar(prhs[1])){ //set the default mxGetString(prhs[1], commandString, COMMAND_STRING_LENGTH); commandString[COMMAND_STRING_LENGTH-1]= '\0'; //guarantee strcmp an end of string character if(strcmp(commandString, "default")) mexErrMsgTxt("Unrecognized second argument. See help MachGetPriorityMex."); threadPolicy=(thread_policy_t)malloc(sizeof(thread_precedence_policy_data_t)); policyCount=THREAD_PRECEDENCE_POLICY_COUNT; policyCountFilled=policyCount; isDefault=TRUE; kernError=thread_policy_get(threadID, THREAD_PRECEDENCE_POLICY, threadPolicy, &policyCountFilled, &isDefault); if (kernError==0) kernError=thread_policy_set(threadID, THREAD_PRECEDENCE_POLICY, threadPolicy, policyCountFilled); free((void*)threadPolicy); break; }else if(mxIsDouble(prhs[1]) && mxGetM(prhs[1]) * mxGetN(prhs[1]) == 1){ //set a specified value threadPolicy=(thread_policy_t)malloc(sizeof(thread_precedence_policy_data_t)); ((thread_precedence_policy_t)threadPolicy)->importance=(integer_t)mxGetPr(prhs[1])[0]; policyCount=THREAD_PRECEDENCE_POLICY_COUNT; policyCountFilled=policyCount; kernError=thread_policy_set(threadID, THREAD_PRECEDENCE_POLICY, threadPolicy, policyCountFilled); } } // Check for and report errors in thread_policy_set: if (kernError!=0) { mexErrMsgTxt("ERROR: Failed to set requested thread scheduling policy! thread_policy_set() failed!"); } }
/** PsychRealtimePriority: Temporarily boost priority to THREAD_TIME_CONSTRAINT_POLICY. PsychRealtimePriority(true) enables realtime-scheduling (like Priority(9) would do in Matlab). PsychRealtimePriority(false) restores scheduling to the state before last invocation of PsychRealtimePriority(true), it undos whatever the previous switch did. We switch to RT scheduling during PsychGetMonitorRefreshInterval() and a few other timing tests in PsychOpenWindow() to reduce measurement jitter caused by possible interference of other tasks. */ psych_bool PsychRealtimePriority(psych_bool enable_realtime) { psych_bool isError; thread_policy_flavor_t flavorConstant; int kernError; task_t threadID; thread_policy_t threadPolicy; static thread_policy_t old_threadPolicy; mach_msg_type_number_t policyCount, policyCountFilled; static mach_msg_type_number_t old_policyCountFilled; boolean_t isDefault; static psych_bool old_enable_realtime = FALSE; static psych_bool oldModeWasStandard = FALSE; if (old_enable_realtime == enable_realtime) { // No transition with respect to previous state -> Nothing to do. return(TRUE); } // Transition requested: old_enable_realtime = enable_realtime; // Determine our threadID: threadID = mach_thread_self(); if (enable_realtime) { // Transition to realtime requested: // Get current scheduling policy and its settings and back it up for later restore: old_threadPolicy = (thread_policy_t) malloc(sizeof(thread_time_constraint_policy_data_t)); policyCount = THREAD_TIME_CONSTRAINT_POLICY_COUNT; old_policyCountFilled = policyCount; isDefault = FALSE; // We check if STANDARD_POLICY is active and query its settings, if so... kernError = thread_policy_get(threadID, THREAD_STANDARD_POLICY, old_threadPolicy, &old_policyCountFilled, &isDefault); if (kernError) { // Failed! old_enable_realtime = FALSE; free(old_threadPolicy); printf("PsychRealtimePriority: ERROR! COULDN'T QUERY CURRENT SCHEDULING SETTINGS!!!\n"); return(FALSE); } // oldModeWasStandard == TRUE --> We need to revert to STANDARD POLICY later... oldModeWasStandard = !isDefault; // printf("PRE-RT: CURRENTLY IN %s mode\n", oldModeWasStandard ? "STANDARD" : "REALTIME"); if (!oldModeWasStandard) { // We are already RT scheduled. Backup settings for later switch-back: policyCount = THREAD_TIME_CONSTRAINT_POLICY_COUNT; old_policyCountFilled = policyCount; isDefault = FALSE; // We check if STANDARD_POLICY is active and query its settings, if so... kernError = thread_policy_get(threadID, THREAD_TIME_CONSTRAINT_POLICY, old_threadPolicy, &old_policyCountFilled, &isDefault); if (kernError) { // Failed! old_enable_realtime = FALSE; free(old_threadPolicy); printf("PsychRealtimePriority: ERROR! COULDN'T QUERY CURRENT RT SCHEDULING SETTINGS!!!\n"); return(FALSE); } } // Switch to our ultra-high priority realtime mode: Guaranteed up to 3 msecs of uninterrupted // runtime as soon as we want to run: Perfect for swap completion timestamping in refresh rate // calibration - our only use-case: PsychSetThreadPriority(NULL, 10, 2); } else { // Transition from RT to Non-RT scheduling requested: We just reestablish the backed-up old // policy: kernError = thread_policy_set(threadID, (oldModeWasStandard) ? THREAD_STANDARD_POLICY : THREAD_TIME_CONSTRAINT_POLICY, old_threadPolicy, old_policyCountFilled); if (kernError) { // Failed! old_enable_realtime = TRUE; free((void*) old_threadPolicy); printf("PsychRealtimePriority: ERROR! COULDN'T SWITCH BACK TO NON-RT SCHEDULING!!!\n"); fflush(NULL); return(FALSE); } // Successfully switchted to RT-Scheduling: free((void*) old_threadPolicy); } // Success. return(TRUE); }