Added some more statistics to the output such as waiting queue length and component utilization by using SimPy Monitors. I couldn't easily use the monitors for the page response times due to the split up nature calls to multiple nodes but for .waitQ and node utilizations they worked out perfectly.
#!/usr/bin/env python
from SimPy.Simulation import *
from random import Random, expovariate, uniform
class Metrics:
metrics = dict()
def Add(self, metricName, frameNumber, value):
if self.metrics.has_key(metricName):
if self.metrics[metricName].has_key(frameNumber):
self.metrics[metricName][frameNumber].append(value)
else:
self.metrics[metricName][frameNumber] = list()
self.metrics[metricName][frameNumber].append(value)
else:
self.metrics[metricName] = dict()
self.metrics[metricName][frameNumber] = list()
self.metrics[metricName][frameNumber].append(value)
def Keys(self):
return self.metrics.keys()
def Mean(self, metricName):
valueArray = list()
if self.metrics.has_key(metricName):
for frame in self.metrics[metricName].keys():
for values in range(len(self.metrics[metricName][frame])):
valueArray.append(self.metrics[metricName][frame][values])
sum = 0.0
for i in range(len(valueArray)):
sum += valueArray[i]
if len(self.metrics[metricName][frame]) != 0:
return sum/len(self.metrics[metricName])
else:
return 0 # Need to learn python throwing exceptions
else:
return 0
class G:
numWS = 1
numAS = 1
numDS = 1
Rnd = random.Random(12345)
PageNames = ["Entry", "Home", "Search", "View", "Login", "Create", "Bid", "Exit" ]
Entry = 0
Home = 1
Search = 2
View = 3
Login = 4
Create = 5
Bid = 6
Exit = 7
WS = 0
AS = 1
DS = 2
CPU = 0
DISK = 1
WS_CPU = 0
WS_DISK = 1
AS_CPU = 2
AS_DISK = 3
DS_CPU = 4
DS_DISK = 5
metrics = Metrics()
# e h s v l c b e
HitCount = [0, 0, 0, 0, 0, 0, 0, 0]
Resources = [[ Resource(1), Resource(1) ], # WS CPU and DISK
[ Resource(1), Resource(1) ], # AS CPU and DISK
[ Resource(1), Resource(1) ]] # DS CPU and DISK
QMon = [[ Monitor(1), Monitor(1)], # WS CPU and DISK
[ Monitor(1), Monitor(1)], # AS CPU and DISK
[ Monitor(1), Monitor(1)]] # DS CPU and DISK
SMon = [[ Monitor(1), Monitor(1)], # WS CPU and DISK
[ Monitor(1), Monitor(1)], # AS CPU and DISK
[ Monitor(1), Monitor(1)]] # DS CPU and DISK
# Enter Home Search View Login Create Bid Exit
ServiceDemand = [ [0.000, 0.008, 0.009, 0.011, 0.060, 0.012, 0.015, 0.000], # WS_CPU
[0.000, 0.030, 0.010, 0.010, 0.010, 0.010, 0.010, 0.000], # WS_DISK
[0.000, 0.000, 0.030, 0.035, 0.025, 0.045, 0.040, 0.000], # AS_CPU
[0.000, 0.000, 0.008, 0.080, 0.009, 0.011, 0.012, 0.000], # AS_DISK
[0.000, 0.000, 0.010, 0.009, 0.015, 0.070, 0.045, 0.000], # DS_CPU
[0.000, 0.000, 0.035, 0.018, 0.050, 0.080, 0.090, 0.000] ] # DS_DISK
# Type B shopper
# 0 1 2 3 4 5 6 7
TransitionMatrix = [ [0.00, 1.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00], # 0
[0.00, 0.00, 0.70, 0.00, 0.10, 0.00, 0.00, 0.20], # 1
[0.00, 0.00, 0.45, 0.15, 0.10, 0.00, 0.00, 0.30], # 2
[0.00, 0.00, 0.00, 0.00, 0.40, 0.00, 0.00, 0.60], # 3
[0.00, 0.00, 0.00, 0.00, 0.00, 0.30, 0.55, 0.15], # 4
[0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 1.00], # 5
[0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 1.00], # 6
[0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00] ] # 7
class RandomPath:
def RowSum(self, Vector):
rowSum = 0.0
for i in range(len(Vector)):
rowSum += Vector[i]
return rowSum
def NextPage(self, T, i):
rowSum = self.RowSum(T[i])
randomValue = G.Rnd.uniform(0, rowSum)
sumT = 0.0
for j in range(len(T[i])):
sumT += T[i][j]
if randomValue < sumT:
break
return j
class ExecuteFrame(Process):
def __init__(self, frameNumber, resource, QMon, SMon, serviceDemand, nodeName, pageName):
Process.__init__(self)
self.frame = frameNumber
self.resource = resource
self.serviceDemand = serviceDemand
self.nodeName = nodeName
self.pageName = pageName
self.QMon = QMon
self.SMon = SMon
def execute(self):
StartUpTime = now()
yield request, self, self.resource
yield hold, self, self.serviceDemand
self.QMon.observe(len(self.resource.waitQ))
self.SMon.observe(self.serviceDemand)
yield release, self, self.resource
R = now() - StartUpTime
G.metrics.Add(self.pageName, self.frame, R)
class CallPage(Process):
def __init__(self, frameNumber, node, pageName):
Process.__init__(self)
self.frame = frameNumber
self.StartUpTime = 0.0
self.currentPage = node
self.pageName = pageName
def execute(self):
if self.currentPage != G.Exit:
print >> sys.stderr, "Working on Frame # ", self.frame, " @ ", now() , " for page ", self.pageName
self.StartUpTime = now()
if G.ServiceDemand[G.WS_CPU][self.currentPage] > 0.0:
wsCPU = ExecuteFrame(self.frame, \
G.Resources[G.WS][G.CPU], \
G.QMon[G.WS][G.CPU], \
G.SMon[G.WS][G.CPU], \
G.ServiceDemand[G.WS_CPU][self.currentPage]/G.numWS, \
"wsCPU", self.pageName)
activate(wsCPU, wsCPU.execute())
if G.ServiceDemand[G.WS_DISK][self.currentPage] > 0.0:
wsDISK = ExecuteFrame(self.frame, \
G.Resources[G.WS][G.DISK], \
G.QMon[G.WS][G.DISK], \
G.SMon[G.WS][G.DISK], \
G.ServiceDemand[G.WS_DISK][self.currentPage]/G.numWS, \
"wsDISK", self.pageName)
activate(wsDISK, wsDISK.execute())
if G.ServiceDemand[G.AS_CPU][self.currentPage] > 0.0:
asCPU = ExecuteFrame(self.frame, \
G.Resources[G.AS][G.CPU], \
G.QMon[G.AS][G.CPU], \
G.SMon[G.AS][G.CPU], \
G.ServiceDemand[G.AS_CPU][self.currentPage]/G.numAS, \
"asCPU", \
self.pageName)
activate(asCPU, asCPU.execute())
if G.ServiceDemand[G.AS_DISK][self.currentPage] > 0.0:
asDISK = ExecuteFrame(self.frame, \
G.Resources[G.AS][G.DISK], \
G.QMon[G.AS][G.DISK], \
G.SMon[G.AS][G.DISK], \
G.ServiceDemand[G.AS_DISK][self.currentPage]/G.numAS, \
"asDISK", \
self.pageName)
activate(asDISK, asDISK.execute())
if G.ServiceDemand[G.DS_CPU][self.currentPage] > 0.0:
dsCPU = ExecuteFrame(self.frame, \
G.Resources[G.DS][G.CPU], \
G.QMon[G.DS][G.CPU], \
G.SMon[G.DS][G.CPU], \
G.ServiceDemand[G.DS_CPU][self.currentPage]/G.numDS, \
"dsCPU", \
self.pageName)
activate(dsCPU, dsCPU.execute())
if G.ServiceDemand[G.DS_DISK][self.currentPage] > 0.0:
dsDISK = ExecuteFrame(self.frame, \
G.Resources[G.DS][G.DISK], \
G.QMon[G.DS][G.DISK], \
G.SMon[G.DS][G.DISK], \
G.ServiceDemand[G.DS_DISK][self.currentPage]/G.numDS, \
"dsDISK", \
self.pageName)
activate(dsDISK, dsDISK.execute())
G.HitCount[self.currentPage] += 1
yield hold, self, 0.00001
class Generator(Process):
def __init__(self, rate, maxT):
Process.__init__(self)
self.name = "Generator"
self.rate = rate
self.maxT = maxT
self.g = Random(11335577)
self.i = 0
self.currentPage = G.Home
def execute(self):
while (now() < self.maxT):
self.i+=1
p = CallPage(self.i,self.currentPage,G.PageNames[self.currentPage])
activate(p,p.execute())
yield hold,self,self.g.expovariate(self.rate)
randomPath = RandomPath()
if self.currentPage == G.Exit:
self.currentPage = G.Home
else:
self.currentPage = randomPath.NextPage(G.TransitionMatrix, self.currentPage)
def main():
Lambda = 4.026*float(sys.argv[1])
maxSimTime = float(sys.argv[2])
initialize()
g = Generator(Lambda, maxSimTime)
activate(g,g.execute())
simulate(until=maxSimTime)
print >> sys.stderr, "Simulated Seconds : ", maxSimTime
print >> sys.stderr, "Page Hits :"
for i in range(len(G.PageNames)):
print >> sys.stderr, "\t", G.PageNames[i], " = ", G.HitCount[i]
print >> sys.stderr, "Throughput : "
for i in range(len(G.PageNames)):
print >> sys.stderr, "\t", G.PageNames[i], " = ", G.HitCount[i]/maxSimTime
print >> sys.stderr, "Mean Response Times:"
for i in G.metrics.Keys():
print >> sys.stderr, "\t", i, " = ", G.metrics.Mean(i)
print >> sys.stderr, "Component Waiting Queues:"
print >> sys.stderr, "\tWeb Server CPU : ", G.QMon[G.WS][G.CPU].mean()
print >> sys.stderr, "\tWeb Server DISK : ", G.QMon[G.WS][G.DISK].mean()
print >> sys.stderr, "\tApplication Server CPU : ", G.QMon[G.AS][G.CPU].mean()
print >> sys.stderr, "\tApplication Server DISK : ", G.QMon[G.AS][G.DISK].mean()
print >> sys.stderr, "\tDatabase Server CPU : ", G.QMon[G.DS][G.CPU].mean()
print >> sys.stderr, "\tDatabase Server DISK : ", G.QMon[G.DS][G.DISK].mean()
print >> sys.stderr, "Component Utilization:"
print >> sys.stderr, "\tWeb Server CPU : ", ((G.SMon[G.WS][G.CPU].mean()*len(G.QMon[G.WS][G.CPU]))/maxSimTime)*100
print >> sys.stderr, "\tWeb Server DISK : ", ((G.SMon[G.WS][G.DISK].mean()*len(G.QMon[G.WS][G.DISK]))/maxSimTime)*100
print >> sys.stderr, "\tApplication Server CPU : ", ((G.SMon[G.AS][G.CPU].mean()*len(G.QMon[G.AS][G.CPU]))/maxSimTime)*100
print >> sys.stderr, "\tApplication Server DISK : ", ((G.SMon[G.AS][G.DISK].mean()*len(G.QMon[G.AS][G.DISK]))/maxSimTime)*100
print >> sys.stderr, "\tDatabase Server CPU : ", ((G.SMon[G.DS][G.CPU].mean()*len(G.QMon[G.DS][G.CPU]))/maxSimTime)*100
print >> sys.stderr, "\tDatabase Server DISK : ", ((G.SMon[G.DS][G.DISK].mean()*len(G.QMon[G.DS][G.DISK]))/maxSimTime)*100
print >> sys.stderr, "Total Component Hits :"
print >> sys.stderr, "\tWeb Server CPU : ", len(G.QMon[G.WS][G.CPU])
print >> sys.stderr, "\tWeb Server DISK : ", len(G.QMon[G.WS][G.DISK])
print >> sys.stderr, "\tApplication Server CPU : ", len(G.QMon[G.AS][G.CPU])
print >> sys.stderr, "\tApplication Server DISK : ", len(G.QMon[G.AS][G.DISK])
print >> sys.stderr, "\tDatabase Server CPU : ", len(G.QMon[G.DS][G.CPU])
print >> sys.stderr, "\tDatabase Server DISK : ", len(G.QMon[G.DS][G.DISK])
print >> sys.stderr, "Total Component Thoughput :"
print >> sys.stderr, "\tWeb Server CPU : ", len(G.QMon[G.WS][G.CPU])/maxSimTime
print >> sys.stderr, "\tWeb Server DISK : ", len(G.QMon[G.WS][G.DISK])/maxSimTime
print >> sys.stderr, "\tApplication Server CPU : ", len(G.QMon[G.AS][G.CPU])/maxSimTime
print >> sys.stderr, "\tApplication Server DISK : ", len(G.QMon[G.AS][G.DISK])/maxSimTime
print >> sys.stderr, "\tDatabase Server CPU : ", len(G.QMon[G.DS][G.CPU])/maxSimTime
print >> sys.stderr, "\tDatabase Server DISK : ", len(G.QMon[G.DS][G.DISK])/maxSimTime
print >> sys.stderr, "Mean Component Svc Demand :"
print >> sys.stderr, "\tWeb Server CPU : ", G.SMon[G.WS][G.CPU].mean()
print >> sys.stderr, "\tWeb Server DISK : ", G.SMon[G.WS][G.DISK].mean()
print >> sys.stderr, "\tApplication Server CPU : ", G.SMon[G.AS][G.CPU].mean()
print >> sys.stderr, "\tApplication Server DISK : ", G.SMon[G.AS][G.DISK].mean()
print >> sys.stderr, "\tDatabase Server CPU : ", G.SMon[G.DS][G.CPU].mean()
print >> sys.stderr, "\tDatabase Server DISK : ", G.SMon[G.DS][G.DISK].mean()
print G.HitCount[G.Home]/maxSimTime, ",", G.metrics.Mean("Home"), ",", G.metrics.Mean("View"), ",", G.metrics.Mean("Search"), ",", G.metrics.Mean("Login"), ",", G.metrics.Mean("Create"), ",", G.metrics.Mean("Bid")
if __name__ == '__main__':
main()