Obsidian is a simulated OS written in ruby that supports process and resource managemen. It's easy to write your own tasks and scheduling algorithms
In case of not having ruby installed in your system refer to ruby install.
Clone this repository:
git clone https://github.com/pablo-co/obsidian
And then execute:
$ bin/setup
Obsidian comes bundled with a CLI. To run this CLI:
Assuming you are on the root of the project
bin/console
A prompt should be shown.
obsidian >> |
You can run many commands on the CLI with the following format: command argument1 argument2 ...
. To see all valid commands and their usage run help
.
obsidian >> help
Usage: command argument1 argument2 ...
Options:
help Display this message
load_task_from_file [file] Load a task from a given YAML file
load_task_from_std_in Load a task from standard input
load_module [file] Load a Ruby file into memory
remove_task [pid] Remove a task from the ready queue
get_task_stats [pid] List all information of a task
set_scheduler [scheduler class] Sets the scheduling algorithm
set_running_time [time] Set Q in for scheduling policies
set_output_delay [delay] Set a delay for writing to the output device
set_automatic_scheduling [true|false] Schedule jobs automatically
step Run the scheduler and dispatcher once
steps [times] Run the scheduler and dispatcher n times
queues Prints the contents of all queues
set_memory_strategy [strategy class] Sets the memory strategy algorithm
process_memory_trace [input] [output] Processes a memory trace and outputs the result to a file
Bug reports, suggestions, updates:
https://github.com/pablo-co/obsidian/issues
You can load tasks from a file and from standard input. In both cases the user defined attributes are:
- priority: The task scheduling priority, it's importance depends on the scheduling algorithm.
- task: The file with the code that will be executed.
Loading a task from a file
obsidian >> load_task_from_file example_file.yml
The file format is exclusively YAML. The keys in the file are the task attributes while it's values are well... it's values.
Example file:
priority: 1
task: examples/sum.rb
Loading a task from standard input
Example user input:
obsidian >> load_task_from_std_in
priority: 1
task: examples/sum.rb
You can remove a task by specifying it's pid. Note: For consistency purposes you can only remove tasks that are in the ready queue.
obsidian >> remove_task [pid]
You can print all the attributes for a given task to the console.
obsidian >> get_task_stats [pid]
You can print all the scheduling queues with their corresponding tasks.
obsidian >> queues
You can change and even write your own scheduling algorithm. To change the algorithm you need to specify the class of this algorithm.
The built-in classes are:
- Obsidian::RoundRobinScheduler (Default)
- Obsidian::SJFScheduler (Schedules according to estimated burst time)
- Obsidian::PrioritySJFScheduler (Schedules according to priority)
obsidian >> set_scheduler Obsidian::SJFScheduler
To write your own algorithm see Scheduler
You can change the maximum time for which a task can run (the default is 10). To remove the burst time limit write infinity
, this will effectively make all scheduling non-preemptive.
To set Q to 10 milliseconds.
obsidian >> set_running_time 10
Remove the maximum burst time. Make all schedulers non-preemptive.
obsidian >> set_running_time infinity
To write to the standard output all programs need to call sys.out
which will write to stdout. This system call takes the task out of the running state and into the waiting queue. The delay is the amount of simulated time it takes to write to this device (the default is 1000).
obsidian >> set_output_delay 1000
You can change whether Obsidian should automatically schedule and dispatch a task or have the user do it manually (by defaults it's true).
To enable it.
obsidian >> set_automatic_scheduling true
To disabled it.
obsidian >> set_automatic_scheduling false
You can also run the scheduler and dispatcher manually. But first you have to disable automatic scheduling.
First make sure you disable automatic scheduling.
obsidian >> set_automatic_scheduling false
Run the scheduler and dispatcher once
obsidian >> step
Run the scheduler and dispatcher n
times.
obsidian >> steps n
You can change the memory management strategy used when processing memory traces.
obsidian >> set_memory_strategy Obisidian::Memory::FirstFitStrategy
There are 3 built-in strategies:
- Obsidian::Memory::FirstFitStrategy
- Obsidian::Memory::BestFitStrategy
- Obsidian::Memory::WorstFitStrategy
To write your own strategy all you have to do is write a class that is a
subclass of Obsidian::Memory::Strategy
and that implements
next_space_available
. See any of the built-in strategies for reference.
You first have to load your custom strategy to memory:
obsidian >> load_module your_custom_strategy.rb
And then you just set it as the current memory strategy:
obsidian >> set_memory_strategy YourCustomStrategy
You can simulate the memory management process with a memory trace file. This file has the following format:
size_of_memory
number_of_available_spaces
starting_address_1, available_space_1
starting_address_2, available_space_2
...
starting_address_N, available_space_N
number_of_processes
pid, arrival_time, duration, size_of_memory
pid, arrival_time, duration, size_of_memory
...
pid, arrival_time, duration, size_of_memory
See examples/memory_trace.txt
for an example memory trace.
To simulate the memory trace:
obsidian >> process_memory_trace examples/memory_trace.txt output.txt
This will parse the memory trace in the first file and output the result of doing memory management with the tasks and memory state given to the output file.
The output given by the example command:
Algorithm: FirstFitStrategy
Assigned processes: 1, 200, 115; 2, 600, 500; 3, 1100, 358; 4, 1458, 200; 5, 1658, 375
Blocked processes:
Memory utilization: 1548 / 4000 = 38.7%
Blocking probability: 5 / 0 = 0.0%
You can run almost any type of ruby code in Obsidian. This code runs in a sandbox thus has some limitations regarding system calls in general. This means you can't make use of files, threads and any other type of operation that interfaces with the operating system.
The only system call currently supported by Obsidian is writing to stdout.
sys.out 'Hello world!'
The are several examples of programs in the examples folder.
You can load the example programs through the CLI to see them in action.
Currently the example programs are:
- examples/calculate_pi.yml
- examples/sum.yml
- examples/exception.yml
obsidian >> load_task_from_file examples/calculate_pi.yml
obsidian >>
[Output (0)]: PI ~= 4.0
[Output (0)]: PI ~= 2.666666666666667
[Output (0)]: PI ~= 3.466666666666667
[Output (0)]: PI ~= 2.8952380952380956
[Output (0)]: PI ~= 3.3396825396825403
obsidian >> set_scheduler Obsidian::RoundRobinScheduler
obsidian >> set_running_time 20
obsidian >> queues
Waiting:
Ready:
Running:
obsidian >> load_task_from_file examples/sum.yml
obsidian >> queues
Waiting:
Ready: (0 | 1 | 220.64876556396484 | 2016-03-30 21:30:37 -0600)
Running:
obsidian >> load_task_from_file examples/calculate_pi.yml
obsidian >>
[Output (1)]: Estimating the value of PI...
[Output (1)]: PI ~= 4.0
obsidian >> queues
Waiting: (1 | 2 | 6.8798065185546875 | 2016-03-30 21:30:42 -0600)
Ready:
Running: (0 | 1 | 1151.9584655761719 | 2016-03-30 21:30:37 -0600)
obsidian >>
[Output (1)]: PI ~= 2.666666666666667
[Output (1)]: PI ~= 3.466666666666667
[Output (1)]: PI ~= 2.8952380952380956
[Output (1)]: PI ~= 3.3396825396825403
obsidian >> remove_task 0
obsidian >> queues
Waiting: (1 | 2 | 6.8798065185546875 | 2016-03-30 21:30:42 -0600)
Ready:
Running:
All documentation is available online at RubyDoc
After checking out the repo, run bin/setup
to install dependencies. Then, run rake test
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
Bug reports and pull requests are welcome on GitHub at https://github.com/pablo-co/obsidian. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
The gem is available as open source under the terms of the MIT License.