ultrastorage: Basic usage

For reproducibility.


In [1]:
import IPython
IPython.__version__


Out[1]:
'3.0.0'

In [89]:
import matplotlib
matplotlib.__version__


Out[89]:
'1.4.3'

In [90]:
import numpy as np
np.__version__


Out[90]:
'1.9.2'

In [91]:
import simpy
simpy.__version__


Out[91]:
'3.0.5'

In [92]:
import ultrastorage
ultrastorage.__version__


Out[92]:
'0.0.1'

Import some ultratorage modules.


In [93]:
# simpy environment embedded in ultrastorage
from ultrastorage import environment

# non-reconfigurable simulator
import ultrastorage.simulator.nonreconfigurable as nonreconfigurable

# insertion politics
import ultrastorage.inserter as inserter

# storage system
import ultrastorage.storagesystem as storagesystem

# item generator
import ultrastorage.itemgenerator as itemgenerator

# timout generator
import ultrastorage.timeoutgenerator as timeoutgenerator

# timed item generator
import ultrastorage.timeditemgenerator as timeditemgenerator

A storage system is composed of several storage units. Each storage unit has a capacity and a number of CPUs.

A storage is system is sais to be

  • regular if all storage units have the same capacity (but they may have different number of CPUs).
  • semi-homogeneous if all storage units have the same number of CPUs (but they may have different capacities).
  • homogeneous if all storage units have the same capacity and the same number of CPUs.

Define an homogeneous storage system with 2 storage units, each with capacity 1000 and 2 CPUs. We let the ultrastorage library infers names for both the storage system and the 2 storage units.


In [94]:
number_of_storage_units = 3
capacity                = 200
cpu                     = 2
storage_system = storagesystem.homogeneous_storage_system_builder(number_of_storage_units, capacity, cpu)
print(storage_system)


(name=HomogeneousStorageSystem-4389143720,storage units=((capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389144896,size=0),(capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389143552,size=0),(capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389145008,size=0)))

Simulating involves defining the simulator itself (what do we do?) and the insertion politics (How do we proceed?). Here we are going to use a non-reconfigurable simulator (i.e., a simulator that does not move items between storage units) that adds item till overflow. This simulator is known by ultrastorage as the ultrastorage.simulator.nonreconfigurable.Overflow object. As for the insertion politics, we use a first-fit strategy, i.e., the item is added to the first large enough storage unit. This insertion politics is known by ultrastorage as the ultrastorage.inserter.FirstFit object.


In [95]:
simulator = nonreconfigurable.Overflow(storage_system, inserter.FirstFit)

Notice that the second argument is a class and not an object instance (we did not write inserter.FirstFit()). This is for avoidng writing the longer inserter.FirstFit(storage_system).

We now turn to defining timed item generator. Let's assume that we produce items with integer size choosen uniformaly between $1$ and $20$ and the delay between two items is an integer choosen uniformaly between $10$ and $20$.


In [96]:
# generate integer item uniformaly in the interval 1..100
item_generator = itemgenerator.IntUniform(1, 100)

# generate integer timeout delay between two item in the interval 1..20
timeout_generator = timeoutgenerator.Uniform(,20)

# combine the item generator and the timeout generator
timed_item_generator = timeditemgenerator.TimedItemGenerator(item_generator, timeout_generator)

# let simpy know about this timed item generator
environment.process(timed_item_generator.run(simulator))


Out[96]:
<Process(run) object at 0x1059c67b8>

Run the simulator.


In [97]:
simulator.run()

Let us first look at the chronology of the simulation. The storage system is shipped with a ultrastorage.itemevent.ItemEventController object that controls the events (each of type ultrastorage.itemevent.ItemEvent).


In [98]:
for item_event in storage_system.item_event_controller:
    print(item_event)


event_type=REQUEST_ADD_ITEM timestamp=345.0 item=54
event_type=START_ADD_ITEM timestamp=345.0 item=54
event_type=REQUEST_ADD_ITEM timestamp=361.0 item=3
event_type=START_ADD_ITEM timestamp=361.0 item=3
event_type=END_ADD_ITEM timestamp=364.0 item=3
event_type=REQUEST_ADD_ITEM timestamp=378.0 item=10
event_type=START_ADD_ITEM timestamp=378.0 item=10
event_type=REQUEST_ADD_ITEM timestamp=382.0 item=52

A snapshot is a picture of a configuration. The snapshot of a storage unit stores internal data at a given time. The snapshot of a storage system stores storage unit snapshots together with storage unit internal data. The storage system object is shipped with a storage system controller that stores and manages all storage system snapshots.


In [99]:
#snapshots = storage_system.snapshot_controller.snapshots()
for (index, snapshot) in enumerate(storage_system.snapshot_controller):
	print("{}: {}\n".format(index+1, str(snapshot)))


1: (timestamp=343.0,((capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389144896,size=0),(capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389143552,size=0),(capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389145008,size=0)))

2: (timestamp=364.0,((capacity=200,count=1,cpu=2,free_space=197,load=0.015,name=StorageUnit-4389144896,size=3),(capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389143552,size=0),(capacity=200,count=0,cpu=2,free_space=200,load=0.0,name=StorageUnit-4389145008,size=0)))

Full reports

Use a reporter (StorageSystemSnapshotReporter) for easy manipulation of storage unit snapshots.


In [100]:
snapshot_reporter = storagesystem.StorageSystemSnapshotReporter(storage_system.snapshot_controller)

Report the size (i.e. total size of the items) of every storage unit at each step of the simulation.


In [101]:
for i, sizes in enumerate(snapshot_reporter.values('size')):
	print("{}: {}".format(i+1, sizes))


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

Report the load (i.e. the ratio of the total size of the items in a storage unit and the capacity) of each storage unit at each step of the simulation.


In [102]:
for i, loads in enumerate(snapshot_reporter.values('load')):
	print("{}: {}".format(i+1, loads))


1: [0.0, 0.0, 0.0]
2: [0.015, 0.0, 0.0]

Report the number of items in each storage unit at each step of the simulation.


In [103]:
for i, counts in enumerate(snapshot_reporter.values('count')):
	print("{}: {}".format(i+1, counts))


1: [0, 0, 0]
2: [1, 0, 0]

Report the average size of the storage units at each step of the simulation.


In [104]:
for i, size in enumerate(snapshot_reporter.average('size')):
	print("{}: {}".format(i+1, size))


1: 0.0
2: 1.0

Report the average load of the storage units at each step of the simulation.


In [105]:
for i, load in enumerate(snapshot_reporter.average('load')):
	print("{}: {}".format(i+1, load))


1: 0.0
2: 0.005

Report the average count of the storage units at each step of the simulation.


In [106]:
for i, count in enumerate(snapshot_reporter.average('count')):
	print("{}: {}".format(i+1, count))


1: 0.0
2: 0.3333333333333333

Report the minimum size of a storage unit at each step of the simulation


In [107]:
for i, size in enumerate(snapshot_reporter.min('size')):
	print("{}: {}".format(i+1, size))


1: 0
2: 0

Report the minimum load of a storage unit at each step of the simulation.


In [108]:
for i, load in enumerate(snapshot_reporter.min('load')):
	print("{}: {}".format(i+1, load))


1: 0.0
2: 0.0

Report the minimum count of a storage unit at each step of the simulation.


In [109]:
for i, count in enumerate(snapshot_reporter.min('count')):
	print("{}: {}".format(i+1, count))


1: 0
2: 0

Report the maximum size of a storage unit at each step of the simulation.


In [110]:
for i, size in enumerate(snapshot_reporter.max('size')):
	print("{}: {}".format(i+1, size))


1: 0
2: 3

Report the maximum load of a storage unit at each step of the simulation.


In [111]:
for i, load in enumerate(snapshot_reporter.max('load')):
	print("{}: {}".format(i+1, load))


1: 0.0
2: 0.015

Report the maximum count of a storage unit at each step of the simulation.


In [112]:
for i, count in enumerate(snapshot_reporter.max('count')):
	print("{}: {}".format(i+1, count))


1: 0
2: 1

In [ ]: