The ioHub Computer Device

Platforms: Windows, OS X, Linux

class psychopy.iohub.devices.Computer[source]

Bases: object

The Computer class does not actually extend the ioHub.devices.Device class. However it is sometimes conceptually convenient to think of the Computer class as a type of ioHub Device.

The Computer class manages the ioHub global clock used to synchronize event times from all ioHub Devices and ioHub DeviceEvents. This universal timebase can be accessed by both the PsychoPy and ioHub Processes.

Note

As of May, 2013 both PsychoPy and ioHub packages implement the same timebase. PsychoPy users accustomed to accessing the timebase with psychopy.core.getTime() or the default psychopy.logging.defaultClock object can also access the timebase with iohub.devices.Computer.getTime. All methods access the same timebase without any user-controlled synchronization!

The Computer class contains methods to allocate the ioHub and PsychoPy Process affinities to particular processing units of the computer if desired. The operating system priority of either process can also be increased.

Note

Setting process affinities and manipulating process priority is not currently supported on OS X.

The Computer class also has methods to monitor current Computer memory and CPU usage. The psutil Process object (if available) can access process level memory, CPU, thread count, disk, and network utilization.

The Computer class contains only static or class level methods, so an instance of the Computer class does not need to be explicitly created. The Computer device can be accessed via the Computer class alone (using ‘iohub.devices.Computer’) or using the ‘self.devices.computer’ attribute of the ioHubExperimentRuntime class.

static enableHighPriority(disable_gc=True)[source]

Sets the priority of the current process to high priority and optionally (default is true) disable the python GC. This is very useful for the duration of a trial, for example, where you enable at start of trial and disable at end of trial.

On Linux, the process is set to a nice level of 10.

This method is not supported on OS X.

Args:
disable_gc (bool): True = Turn of the Python Garbage Collector. False = Leave the Garbage Collector running. Default: True
static enableRealTimePriority(disable_gc=True)[source]

Sets the priority of the current process to real-time priority class and optionally (default is true) disable the python GC. This is very useful for the duration of a trial, for example, where you enable at start of trial and disable at end of trial. Note that on Windows 7 it is not possible to set a process to real-time priority, so high-priority is used instead.

On Linux, the process is set to a nice level of 16.

This method is not supported on OS X.

Args:
disable_gc (bool): True = Turn of the Python Garbage Collector. False = Leave the Garbage Collector running. Default: True
static disableRealTimePriority()[source]

Sets the priority of the Current Process back to normal priority and enables the python GC. In general you would call enableRealTimePriority() at start of trial and call disableHighPriority() at end of trial.

On Linux, sets the nice level of the process back to the value being used prior to the call to enableRealTimePriority()

This method is not supported on OS X.

Return:
None
static disableHighPriority()[source]

Sets the priority of the Current Process back to normal priority and enables the python GC. In general you would call enableHighPriority() at start of trial and call disableHighPriority() at end of trial.

On Linux, sets the nice level of the process back to the value being used prior to the call to enableHighPriority()

This method is not supported on OS X.

Return:
None
static getProcessingUnitCount()[source]

Return the number of processing units available on the current computer. Processing Units include: cpu’s, cpu cores, and hyper threads.

Notes:

  • processingUnitCount = num_cpus*num_cores_per_cpu*num_hyperthreads.
  • For single core CPU’s, num_cores_per_cpu = 1.
  • For CPU’s that do not support hyperthreading, num_hyperthreads = 1, otherwise num_hyperthreads = 2.
Args:
None
Returns:
int: the number of processing units on the computer.
static getProcessAffinities()[source]

Retrieve the current PsychoPy Process affinity list and ioHub Process affinity list.

For example, on a 2 core CPU with hyper-threading, the possible ‘processor’ list would be [0,1,2,3], and by default both the PsychoPy and ioHub Processes can run on any of these ‘processors’, so:

psychoCPUs,ioHubCPUS=Computer.getProcessAffinities()
print psychoCPUs,ioHubCPUS

>> [0,1,2,3], [0,1,2,3]

If Computer.setProcessAffinities was used to set the PsychoPy Process to core 1 (index 0 and 1) and the ioHub Process to core 2 (index 2 and 3), with each using both hyper threads of the given core, the set call would look like:

Computer.setProcessAffinities([0,1],[2,3])

psychoCPUs,ioHubCPUS=Computer.getProcessAffinities()
print psychoCPUs,ioHubCPUS

>> [0,1], [2,3]

If the ioHub is not being used (i.e self.hub == None), then only the PsychoPy Process affinity list will be returned and None will be returned for the ioHub Process affinity:

psychoCPUs,ioHubCPUS=Computer.getProcessAffinities()
print psychoCPUs,ioHubCPUS

>> [0,1,2,3], None

But in this case, why are you using the ioHub package at all? ;)

This method is not supported on OS X.

Args:
None
Returns:
(list,list) Tuple of two lists: PsychoPy Process affinity ID list and ioHub Process affinity ID list.
static setProcessAffinities(experimentProcessorList, ioHubProcessorList)[source]

Sets the processor affinity for the PsychoPy Process and the ioHub Process.

For example, on a 2 core CPU with hyper-threading, the possible ‘processor’ list would be [0,1,2,3], and by default both the experiment and ioHub server processes can run on any of these ‘processors’, so to have both processes have all processors available (which is the default), you would call:

Computer.setProcessAffinities([0,1,2,3], [0,1,2,3])

# check the process affinities
psychoCPUs,ioHubCPUS=Computer.getProcessAffinities()
print psychoCPUs,ioHubCPUS

>> [0,1,2,3], [0,1,2,3]

based on the above CPU example.

If setProcessAffinities was used to set the experiment process to core 1 (index 0,1) and the ioHub server process to core 2 (index 2,3), with each using both hyper threads of the given core, the set call would look like:

Computer.setProcessAffinities([0,1],[2,3])

# check the process affinities
psychoCPUs,ioHubCPUS=Computer.getProcessAffinities()
print psychoCPUs,ioHubCPUS

>> [0,1], [2,3]
Args:

experimentProcessorList (list): list of int processor ID’s to set the PsychoPy Process affinity to. An empty list means all processors.

ioHubProcessorList (list): list of int processor ID’s to set the ioHub Process affinity to. An empty list means all processors.

Returns:
None
static autoAssignAffinities()[source]

Auto sets the PsychoPy Process and ioHub Process affinities based on some very simple logic.

It is not known at this time if the implementation of this method makes any sense in terms of actually improving performance. Field tests and feedback will need to occur, based on which the algorithm can be improved.

Currently:

  • If the system is detected to have 1 processing unit, or greater than 8 processing units, nothing is done by the method.
  • For a system that has two processing units, the PsychoPy Process is assigned to index 0, ioHub Process assigned to 1.
  • For a system that has four processing units, the PsychoPy Process is assigned to index’s 0,1 and the ioHub Process assigned to 2,3.
  • For a system that has eight processing units, the PsychoPy Process is assigned to index 2,3, ioHub Process assigned to 4,5. All other processes running on the OS are attempted to be assigned to indexes 0,1,6,7.
Args:
None
Returns:
None
static getCurrentProcessAffinity()[source]

Returns a list of ‘processor’ ID’s (from 0 to Computer.processingUnitCount-1) that the current (calling) process is able to run on.

Args:
None
Returns:
None
static setCurrentProcessAffinity(processorList)[source]

Sets the list of ‘processor’ ID’s (from 0 to Computer.processingUnitCount-1) that the current (calling) process should only be allowed to run on.

Args:
processorList (list): list of int processor ID’s to set the current Process affinity to. An empty list means all processors.
Returns:
None
static setProcessAffinityByID(process_id, processor_list)[source]

Sets the list of ‘processor’ ID’s (from 0 to Computer.processingUnitCount-1) that the process with the provided OS Process ID is able to run on.

Args:

processID (int): The system process ID that the affinity should be set for.

processorList (list): list of int processor ID’s to set process with the given processID too. An empty list means all processors.

Returns:
None
static getProcessAffinityByID(process_id)[source]

Returns a list of ‘processor’ ID’s (from 0 to Computer.processingUnitCount-1) that the process with the provided processID is able to run on.

Args:
processID (int): The system process ID that the affinity should be set for.
Returns:
processorList (list): list of int processor ID’s to set process with the given processID too. An empty list means all processors.
static setAllOtherProcessesAffinity(processor_list, exclude_process_id_list=[])[source]

Sets the affinity for all OS Processes other than those specified in the exclude_process_id_list, to the processing unit indexes specified in processor_list. Valid values in the processor_list are between 0 to Computer.processingUnitCount-1.

exclude_process_id_list should be a list of OS Process ID integers, or an empty list (indicating to set the affiinty to all processing units).

Note that the OS may not allow the calling process to set the affinity of every other process running on the system. For example, some system level processing can not have their affinity set by a user level application.

However, in general, many processes can have their affinity set by another user process.

Args:

processor_list (list): list of int processor ID’s to set all OS Processes to. An empty list means all processors.

exclude_process_id_list (list): A list of process ID’s that should not have their process affinity settings changed.

Returns:
None
static currentTime()[source]

Alias for Computer.currentSec()

static currentSec()[source]

Returns the current sec.msec-msec time of the system.

The underlying timer that is used is based on OS and Python version. Three requirements exist for the ioHub time base implementation:

  • The Python interpreter does not apply an offset to the times returned based on when the timer module being used was loaded or when the timer fucntion first called was first called.
  • The timer implementation used must be monotonic and report elapsed time between calls, ‘not’ CPU usage time.
  • The timer implementation must provide a resolution of 50 usec or better.

Given the above requirements, ioHub selects a timer implementation as follows:

  • On Windows, the Windows Query Performance Counter API is used using ctypes access.
  • On other OS’s, if the Python version being used is 2.6 or lower, time.time is used. For Python 2.7 and above, the timeit.default_timer function is used.
Args:
None
Returns:
None
static getTime()[source]

Alias for Computer.currentSec()

static getPhysicalSystemMemoryInfo()[source]

Return a class containing information about current memory usage.

Args:
None
Returns:
vmem: (total=long, available=long, percent=float, used=long, free=long)

Where:

  • vmem.total: the total amount of memory in bytes.
  • vmem.available: the available amount of memory in bytes.
  • vmem.percent: the percent of memory in use by the system.
  • vmem.used: the used amount of memory in bytes.
  • vmem.free: the amount of memory that is free in bytes.On Windows, this is the same as vmem.available.
static getCPUTimeInfo(percpu=False)[source]

Return information about the computers CPU usage.

Args:
percpu (bool): If True, a list of cputimes objects is returned, one for each processing unit for the computer. If False, only a single cputimes object is returned.
Returns:
object: (user=float, system=float, idle=float)
static getCurrentProcess()[source]

Get the current / Local process.

On Windows and Linux, this is a psutil.Process class instance. On OS X, it is a multiprocessing.Process instance.

Args:
None
Returns:
object: Process object for the current system process.
static getIoHubProcess()[source]

Get the ioHub Process.

On Windows and Linux, this is a psutil.Process class instance. On OS X, it is a multiprocessing.Process instance.

Args:
None
Returns:
object: Process object for the ioHub Process.

Computer Device Default Configuration Settings

The computer Device is enabled automatically and has no configuration settings in the iohub_config.yaml.

Computer Device Events

The Computer Device does not generate any ioHub Events.

Notes and Considerations

None at this time.