While the intended goal of the Locusts project ("Use Available Resources Dynamically") is simply stated, it involves a number of complications, that must be considered prior to realisation.
If a resource (be it storage, computation, or a network connection) is to be used, it must first be discovered by the system. This is most easily accomplished, if the resources in question periodically announce their presence and capabilities. These announcements can then be cached and later acted upon by devices looking for somewhere to offload jobs.
This service should be very lightweight as to not create too much network traffic or put undue strain on the announcing machine, and this has in the Locusts project been realised through the Presence library, which is both lightweight and cross-platform.
Data and Task Mobility
If a computation is be done at some other computer, the necessary code for the computation must first be transferred as well as the data upon which the code is to work. This has a number of complications: What kind of code? How much data? This has been met with various approaches over the history of Cyber Foraging. Some systems require that all services be installed in advance (which is simple, but restricts cyber foraging to specific machines in specific locales). Other allows for the installation of foreign binary code, but runs it in freshly instantiated virtual machines (which is a costly and slow operation).
We have in the Locusts project chosen to prioritise flexibility and mobility, so our mobile code is simply Python code, which can be easily transferred from one machine to another without requiring a specific operating system or CPU.
Moving data from one machine to another may be simple, but has important implications for cyber foraging. As we wish to complete tasks as quickly as possible, we need take the time need to transfer data into consideration, when choosing a machine to offload to: If we have not complete the transfer (let alone the result) before we move out of network range, the effort has been wasted. Thus, it is important to ensure that data is moved about as little as possible, and if it is to be moved, it should be moved along the best connections available.
It would be ill advised to run mobile code without any sort of security precautions. Not only that, but mobile code may well need special services to e.g. access resources. Therefore, an execution environment is needed to securely contain the code that should be run locally and to provide it with any needed services. As we in the Locusts project has chosen to use mobile code to facilitate flexibility, we must also take care of the added complexities of handling the mobile code. This involves a number of issues:
- Security: The mobile code should not have access (or be able to gain access to) sensitive information or potentially harmful operations. This means that mobile code is prevented from accessing e.g. general file operations and other basic system functions out of a tightly restricted area on the host machine.
- Monitoring: Programs will on occasion fail or enter infinite loops. This must be detected and handled, as it would be unacceptable that a host machine should become burdened with run-away processes. To address this, we implement our execution environment in Stackless Python, which provides fine grained thread and process control. If a job is not completed in its allotted time, it is terminated.
- Temporary storage: While the mobile code is denied general access to the host machine, they may still require some storage - certainly for temporarily storing results.
Scheduling and Profiling
If we are to offload jobs to other machines, there are quite a few possibilities that must be taken into account:
- If our local device is the most powerful machine around, it may not make sense to offload to other, lesser machines.
- Likewise, it would be foolish to offload to a weak machine, if a stronger one is available.
- A machine may be stronger than others available, but if it is too busy to take on new jobs, a weaker machine would be a better candidate.
- A machine may perform well on a generic benchmark, but that does not necessarily translate to good performance when doing specialised tasks.
- When considering which machine to pick, the time used to transfer data back and forth must be taken into account.
These considerations are all handled by the scheduler, which, together with the discovery mechanism, keeps track of available machines, their respective strengths and past performance. The scheduler can have machines benchmark to judge their general strengths, and it can also keep a history of how well the machines have performed doing specific task in the past. The latter can be used, not only to judge between known machines with known performance, but also to inform the scheduler about how "heavy" a given task may be, which is valuable when considering scheduling it for an unknown machine.