class SsdTPTest(DeviceTest): ''' A class to carry out the Throughput test. ''' ##Labels of block sizes for throughput test bsLabels = [ "1024k", "64k", "8k", "4k", "512", ] def __init__(self, testname, device, options): ''' Constructor. ''' super(SsdTPTest, self).__init__(testname, device, options) ## A list of matrices with the collected fio measurement values of each round. self.__roundMatrices = [] self.__stdyState = StdyState() def getRndMatrices(self): return self.__roundMatrices def getStdyState(self): return self.__stdyState def toLog(self): ''' Log information about the steady state and how it has been reached. ''' logging.info("Round matrices: ") logging.info(self.__roundMatrices) self.getStdyState().toLog() def testRound(self, bs): ''' Carry out one test round of the throughput test. Read and Write throughput is tested with the given block size @param bs The current block size to use. @return Read and Write bandwidths [tpRead,tpWrite] ''' self.getFioJob().addKVArg("bs", bs) jobOut = '' tpRead = 0 #read bandwidth tpWrite = 0 #write bandwidth #start read tests self.getFioJob().addKVArg("rw", "read") call, jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("Read TP test:") logging.info(jobOut) logging.info("######") tpRead = self.getFioJob().getTPRead(jobOut) #start write tests self.getFioJob().addKVArg("rw", "write") call, jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("Write TP test:") logging.info(jobOut) logging.info("######") tpWrite = self.getFioJob().getTPWrite(jobOut) return [tpRead, tpWrite] def runRounds(self): ''' Carry out the throughput/bandwidth test rounds and check if the steady state is reached. @return True if the steady state has been reached, False if not. ''' stdyValsWrite = deque([]) #List of 1M sequential write IOPS xrangesWrite = deque([]) #Rounds of current measurement window #rounds are the same for IOPS and throughput for j in SsdTPTest.bsLabels: try: self.getDevice().secureErase() except RuntimeError: logging.error("# Could not carry out secure erase for " + self.getDevice().getDevPath()) raise tpRead_l = [] tpWrite_l = [] logging.info("#################") logging.info("Current block size. " + str(j)) for i in range(StdyState.testRnds): logging.info("######") logging.info("Round nr. " + str(i)) tpRead, tpWrite = self.testRound(j) tpRead_l.append(tpRead) tpWrite_l.append(tpWrite) #if the rounds have been set by steady state for 1M block size #we need to carry out only i rounds for the other block sizes #as steady state has already been reached if self.getStdyState().getRnds() != 0 and self.getStdyState( ).getRnds() == i: self.getRndMatrices().append([tpRead_l, tpWrite_l]) break # Use 1M block sizes sequential write for steady state detection if j == "1024k": stdyValsWrite.append(tpWrite) xrangesWrite.append(i) if i > 4: xrangesWrite.popleft() stdyValsWrite.popleft() #check if the steady state has been reached in the last 5 rounds if i >= 4: steadyState = self.getStdyState().checkSteadyState( xrangesWrite, stdyValsWrite, i) #reached a steady state if steadyState == True: logging.info("Reached steady state at round %d", i) #running from 0 to 24 if i == ((StdyState.testRnds) - 1): self.getStdyState().setReachStdyState(False) logging.warn( "#Did not reach steady state for bs %s", j) #In both cases we are done with steady state checking if steadyState == True or i == ((StdyState.testRnds) - 1): self.getRndMatrices().append([tpRead_l, tpWrite_l]) #Done with 1M block size break #Return current steady state return self.getStdyState().isSteady() def run(self): ''' Start the rounds, log the steady state infos. @return True if all tests were run ''' logging.info("########### Starting Throughput Test ###########") steadyState = self.runRounds() if steadyState == False: logging.info( "# Steady State has not been reached for Throughput Test.") self.toLog() return True def toXml(self, root): ''' Get the Xml representation of the test. @param root Name of the new root Xml node @return An xml root element containing the information about the test ''' r = etree.Element(root) # Add Fio version to xml self.getFioJob().appendXml(r) # Add the options to xml self.getOptions().appendXml(r) data = json.dumps(self.__roundMatrices) e = etree.SubElement(r, 'roundmat') e.text = data self.getStdyState().appendXml(r) return r def fromXml(self, root): ''' Load and set from an XML representation of a test. @param root Name of root element from which to load values ''' logging.info("########### Loading TP test from " + self.getTestname() + ".xml ###########") self.__roundMatrices = json.loads(root.findtext('roundmat')) self.__stdyState.fromXml(root) self.getFioJob().fromXml(root) self.getOptions().fromXml(root) self.toLog() def genPlots(self): ''' Generate plots for throughput. ''' import plots.genPlots as pgp pgp.tpRWStdyStConvPlt(self) pgp.stdyStVerPlt(self, "TP") pgp.tpMes2DPlt(self)
class SsdLatencyTest(DeviceTest): ''' Representing a Latency test for a ssd based device. ''' ##Percentages of mixed workloads. mixWlds = [100, 65, 0] ##Labels of block sizes. bsLabels = ["8k", "4k", "512"] def __init__(self, testname, device, options=None): ''' Constructor. ''' ## Keep user options self.__userOptions = options if options != None: #For latency the specification says to use 1 job/thread, 1 outstanding IO wsoptions = Options(1, 1) if options.getXargs() != None: wsoptions.setXargs(options.getXargs()) super(SsdLatencyTest, self).__init__(testname, device, wsoptions) ## A list of matrices with the collected fio measurement values of each round. self.__roundMatrices = [] self.__stdyState = StdyState() self.getFioJob().addKVArg("rw", "randrw") def getRndMatrices(self): return self.__roundMatrices def getStdyState(self): return self.__stdyState def toLog(self): ''' Log information about the steady state and how it has been reached. ''' logging.info("Round matrices: ") logging.info(self.__roundMatrices) self.getStdyState().toLog() def testRound(self): ''' Carry out one latency test round. The round consists of two inner loops: one iterating over the percentage of random reads/writes in the mixed workload, the other over different block sizes. @return A matrix containing [min,max,mean] latencies of the round. ''' jobOut = '' rndMatrix = [] for i in SsdLatencyTest.mixWlds: rwRow = [] for j in SsdLatencyTest.bsLabels: self.getFioJob().addKVArg("rwmixread", str(i)) self.getFioJob().addKVArg("bs", j) call, jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("mixLoad: " + str(i)) logging.info("bs: " + j) logging.info(jobOut) logging.info("######") if i == 65: #if we have a mixed workload weight the latencies l = [0, 0, 0] r = self.getFioJob().getReadLats(jobOut) w = self.getFioJob().getWriteLats(jobOut) #FIXME Is this also correct for Min and Max? l[0] = (0.65 * r[0]) + (0.35 * w[0]) l[1] = (0.65 * r[1]) + (0.35 * w[1]) l[2] = (0.65 * r[2]) + (0.35 * w[2]) else: l = self.getFioJob().getTotLats(jobOut) rwRow.append(l) rndMatrix.append(rwRow) return rndMatrix def runRounds(self): ''' Carry out the latency test rounds and check if the steady state is reached. For a maximum of 25 rounds the test loop is carried out. After each test round we check for a measurement window of the last 5 rounds if the steady state has been reached. @return True if the steady state has been reached, False if not. ''' rndMatrix = [] steadyValues = deque([]) xranges = deque([]) #Rounds of current measurement window for i in range(StdyState.testRnds): logging.info("#################") logging.info("Round nr. " + str(i)) rndMatrix = self.testRound() self.getRndMatrices().append(rndMatrix) #Latencies always consist of [min,max,mean] latency #Take mean/average for steady state detection steadyValues.append(rndMatrix[-1][-2][2]) xranges.append(i) if i > 4: xranges.popleft() steadyValues.popleft() #check if the steady state has been reached in the last 5 rounds if i >= 4: steadyState = self.getStdyState().checkSteadyState( xranges, steadyValues, i) if steadyState == True: break #Return current steady state return self.getStdyState().isSteady() def run(self): ''' Start the rounds, log the steady state infos. @return True if all tests were run ''' try: self.getDevice().secureErase() except RuntimeError: logging.error("# Could not carry out secure erase for " + self.getDevice().getDevPath()) raise try: if self.__userOptions == None: self.getDevice().precondition(1, 1) else: if self.__userOptions.getNj() != None: nj = self.__userOptions.getNj() if self.__userOptions.getIod() != None: iod = self.__userOptions.getIod() self.getDevice().precondition(nj, iod) except RuntimeError: logging.error("# Could not carry out preconditioning for " + self.getDevice().getDevPath()) raise logging.info("########### Starting Latency Test ###########") steadyState = self.runRounds() if steadyState == False: logging.info( "# Steady State has not been reached for Latency Test.") self.toLog() return True def toXml(self, root): ''' Get the Xml representation of the test. @param root Name of the new root Xml node @return An xml root element containing the information about the test ''' r = etree.Element(root) # Add Fio version to xml self.getFioJob().appendXml(r) # Add the options to xml self.getOptions().appendXml(r) data = json.dumps(self.__roundMatrices) e = etree.SubElement(r, 'roundmat') e.text = data self.getStdyState().appendXml(r) return r def fromXml(self, root): ''' Load and set from an XML representation of a test. @param root Name of root element from which to load values ''' logging.info("########### Loading latency test from " + self.getTestname() + ".xml ###########") self.__roundMatrices = json.loads(root.findtext('roundmat')) self.__stdyState.fromXml(root) self.getFioJob().fromXml(root) self.getOptions().fromXml(root) self.toLog() def genPlots(self): ''' Generate plots for latency. ''' import plots.genPlots as pgp pgp.stdyStConvPlt(self, "LAT") pgp.stdyStVerPlt(self, "LAT") pgp.mes2DPlt(self, "avg-LAT") pgp.mes2DPlt(self, "max-LAT") pgp.latMes3DPlt(self)
class SsdIopsTest(DeviceTest): ''' Representing an IOPS test for a ssd based device. ''' ##Labels of block sizes bsLabels = ["1024k", "128k", "64k", "32k", "16k", "8k", "4k", "512"] ##Percentages of mixed workloads mixWlds = [100, 95, 65, 50, 35, 5, 0] def __init__(self, testname, device, options=None): ''' Constructor. ''' super(SsdIopsTest, self).__init__(testname, device, options) ## A list of matrices with the collected fio measurement values of each round. self.__roundMatrices = [] self.__stdyState = StdyState() self.getFioJob().addKVArg("rw", "randrw") def getRndMatrices(self): return self.__roundMatrices def getStdyState(self): return self.__stdyState def toLog(self): ''' Log information about the steady state and how it has been reached. ''' logging.info("Round matrices: ") logging.info(self.__roundMatrices) self.getStdyState().toLog() def testRound(self): ''' Carry out one IOPS test round. The round consists of two inner loops: one iterating over the percentage of random reads/writes in the mixed workload, the other over different block sizes. @return A matrix containing the sum of average IOPS. ''' jobOut = '' #Fio job output rndMatrix = [] for i in SsdIopsTest.mixWlds: rwRow = [] for j in SsdIopsTest.bsLabels: self.getFioJob().addKVArg("rwmixread", str(i)) self.getFioJob().addKVArg("bs", j) call, jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("mixLoad: " + str(i)) logging.info("bs: " + j) logging.info(jobOut) logging.info("######") rwRow.append(self.getFioJob().getIOPS(jobOut)) rndMatrix.append(rwRow) return rndMatrix def runRounds(self): ''' Carry out the IOPS test rounds and check if the steady state is reached. For a maximum of 25 rounds the test loop is carried out. After each test round we check for a measurement window of the last 5 rounds if the steady state has been reached. @return True if the steady state has been reached, False if not. ''' rndMatrix = [] steadyValues = deque([]) #List of 4k random writes IOPS xranges = deque([]) #Rounds of current measurement window for i in range(StdyState.testRnds): logging.info("#################") logging.info("Round nr. " + str(i)) rndMatrix = self.testRound() self.getRndMatrices().append(rndMatrix) # Use the last row and its next to last value #-> 0/100% r/w and 4k for steady state detection steadyValues.append(rndMatrix[-1][-2]) xranges.append(i) if i > 4: xranges.popleft() steadyValues.popleft() #check if the steady state has been reached in the last 5 rounds if i >= 4: steadyState = self.getStdyState().checkSteadyState( xranges, steadyValues, i) if steadyState == True: break #Return current steady state return self.getStdyState().isSteady() def run(self): ''' Start the rounds, log the steady state infos. @return True if all tests were run ''' try: self.getDevice().secureErase() except RuntimeError: logging.error("# Could not carry out secure erase for " + self.getDevice().getDevPath()) raise try: if self.getOptions() == None: self.getDevice().precondition(1, 1) else: if self.getOptions().getNj() != None: nj = self.getOptions().getNj() if self.getOptions().getIod() != None: iod = self.getOptions().getIod() self.getDevice().precondition(nj, iod) except RuntimeError: logging.error("# Could not carry out preconditioning for " + self.getDevice().getDevPath()) raise logging.info("########### Starting IOPS Test ###########") steadyState = self.runRounds() if steadyState == False: logging.info("# Steady State has not been reached for IOPS Test.") self.toLog() return True def toXml(self, root): ''' Get the Xml representation of the test. @param root Name of the new root Xml node @return An xml root element containing the information about the test ''' r = etree.Element(root) # Add Fio version to xml self.getFioJob().appendXml(r) # Add the options to xml self.getOptions().appendXml(r) data = json.dumps(self.__roundMatrices) e = etree.SubElement(r, 'roundmat') e.text = data self.getStdyState().appendXml(r) return r def fromXml(self, root): ''' Load and set from an XML representation of a test. @param root Name of root element from which to load values ''' logging.info("########### Loading IOPS test from " + self.getTestname() + ".xml ###########") self.__roundMatrices = json.loads(root.findtext('roundmat')) self.__stdyState.fromXml(root) self.getFioJob().fromXml(root) self.getOptions().fromXml(root) self.toLog() def genPlots(self): ''' Generate plots for IOPS. ''' import plots.genPlots as pgp pgp.stdyStConvPlt(self, "IOPS") pgp.stdyStVerPlt(self, "IOPS") pgp.mes2DPlt(self, "IOPS") pgp.mes3DPlt(self, "IOPS")
class SsdTPTest(DeviceTest): ''' A class to carry out the Throughput test. ''' ##Labels of block sizes for throughput test bsLabels = ["1024k","64k","8k","4k","512",] def __init__(self,testname,device,options): ''' Constructor. ''' super(SsdTPTest,self).__init__(testname,device,options) ## A list of matrices with the collected fio measurement values of each round. self.__roundMatrices = [] self.__stdyState = StdyState() def getRndMatrices(self): return self.__roundMatrices def getStdyState(self): return self.__stdyState def toLog(self): ''' Log information about the steady state and how it has been reached. ''' logging.info("Round matrices: ") logging.info(self.__roundMatrices) self.getStdyState().toLog() def testRound(self,bs): ''' Carry out one test round of the throughput test. Read and Write throughput is tested with the given block size @param bs The current block size to use. @return Read and Write bandwidths [tpRead,tpWrite] ''' self.getFioJob().addKVArg("bs",bs) jobOut = '' tpRead = 0 #read bandwidth tpWrite = 0#write bandwidth #start read tests self.getFioJob().addKVArg("rw","read") call,jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("Read TP test:") logging.info(jobOut) logging.info("######") tpRead = self.getFioJob().getTPRead(jobOut) #start write tests self.getFioJob().addKVArg("rw","write") call,jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("Write TP test:") logging.info(jobOut) logging.info("######") tpWrite = self.getFioJob().getTPWrite(jobOut) return [tpRead,tpWrite] def runRounds(self): ''' Carry out the throughput/bandwidth test rounds and check if the steady state is reached. @return True if the steady state has been reached, False if not. ''' stdyValsWrite = deque([])#List of 1M sequential write IOPS xrangesWrite = deque([])#Rounds of current measurement window #rounds are the same for IOPS and throughput for j in SsdTPTest.bsLabels: try: self.getDevice().secureErase() except RuntimeError: logging.error("# Could not carry out secure erase for "+self.getDevice().getDevPath()) raise tpRead_l = [] tpWrite_l = [] logging.info("#################") logging.info("Current block size. "+str(j)) for i in range(StdyState.testRnds): logging.info("######") logging.info("Round nr. "+str(i)) tpRead,tpWrite = self.testRound(j) tpRead_l.append(tpRead) tpWrite_l.append(tpWrite) #if the rounds have been set by steady state for 1M block size #we need to carry out only i rounds for the other block sizes #as steady state has already been reached if self.getStdyState().getRnds() != 0 and self.getStdyState().getRnds() == i: self.getRndMatrices().append([tpRead_l,tpWrite_l]) break # Use 1M block sizes sequential write for steady state detection if j == "1024k": stdyValsWrite.append(tpWrite) xrangesWrite.append(i) if i > 4: xrangesWrite.popleft() stdyValsWrite.popleft() #check if the steady state has been reached in the last 5 rounds if i >= 4: steadyState = self.getStdyState().checkSteadyState(xrangesWrite,stdyValsWrite,i) #reached a steady state if steadyState == True: logging.info("Reached steady state at round %d",i) #running from 0 to 24 if i == ((StdyState.testRnds) - 1): self.getStdyState().setReachStdyState(False) logging.warn("#Did not reach steady state for bs %s",j) #In both cases we are done with steady state checking if steadyState == True or i == ((StdyState.testRnds) - 1): self.getRndMatrices().append([tpRead_l,tpWrite_l]) #Done with 1M block size break #Return current steady state return self.getStdyState().isSteady() def run(self): ''' Start the rounds, log the steady state infos. @return True if all tests were run ''' logging.info("########### Starting Throughput Test ###########") steadyState = self.runRounds() if steadyState == False: logging.info("# Steady State has not been reached for Throughput Test.") self.toLog() return True def toXml(self,root): ''' Get the Xml representation of the test. @param root Name of the new root Xml node @return An xml root element containing the information about the test ''' r = etree.Element(root) # Add Fio version to xml self.getFioJob().appendXml(r) # Add the options to xml self.getOptions().appendXml(r) data = json.dumps(self.__roundMatrices) e = etree.SubElement(r,'roundmat') e.text = data self.getStdyState().appendXml(r) return r def fromXml(self,root): ''' Load and set from an XML representation of a test. @param root Name of root element from which to load values ''' logging.info("########### Loading TP test from "+self.getTestname()+".xml ###########") self.__roundMatrices = json.loads(root.findtext('roundmat')) self.__stdyState.fromXml(root) self.getFioJob().fromXml(root) self.getOptions().fromXml(root) self.toLog() def genPlots(self): ''' Generate plots for throughput. ''' import plots.genPlots as pgp pgp.tpRWStdyStConvPlt(self) pgp.stdyStVerPlt(self,"TP") pgp.tpMes2DPlt(self)
class SsdLatencyTest(DeviceTest): ''' Representing a Latency test for a ssd based device. ''' ##Percentages of mixed workloads. mixWlds = [100,65,0] ##Labels of block sizes. bsLabels = ["8k","4k","512"] def __init__(self,testname,device,options=None): ''' Constructor. ''' ## Keep user options self.__userOptions = options if options != None: #For latency the specification says to use 1 job/thread, 1 outstanding IO wsoptions = Options(1,1) if options.getXargs() != None: wsoptions.setXargs(options.getXargs()) super(SsdLatencyTest,self).__init__(testname,device,wsoptions) ## A list of matrices with the collected fio measurement values of each round. self.__roundMatrices = [] self.__stdyState = StdyState() self.getFioJob().addKVArg("rw","randrw") def getRndMatrices(self): return self.__roundMatrices def getStdyState(self): return self.__stdyState def toLog(self): ''' Log information about the steady state and how it has been reached. ''' logging.info("Round matrices: ") logging.info(self.__roundMatrices) self.getStdyState().toLog() def testRound(self): ''' Carry out one latency test round. The round consists of two inner loops: one iterating over the percentage of random reads/writes in the mixed workload, the other over different block sizes. @return A matrix containing [min,max,mean] latencies of the round. ''' jobOut = '' rndMatrix = [] for i in SsdLatencyTest.mixWlds: rwRow = [] for j in SsdLatencyTest.bsLabels: self.getFioJob().addKVArg("rwmixread",str(i)) self.getFioJob().addKVArg("bs",j) call,jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("mixLoad: " +str(i)) logging.info("bs: "+j) logging.info(jobOut) logging.info("######") if i == 65: #if we have a mixed workload weight the latencies l = [0,0,0] r = self.getFioJob().getReadLats(jobOut) w = self.getFioJob().getWriteLats(jobOut) #FIXME Is this also correct for Min and Max? l[0] = (0.65 * r[0]) + (0.35 * w[0]) l[1] = (0.65 * r[1]) + (0.35 * w[1]) l[2] = (0.65 * r[2]) + (0.35 * w[2]) else: l = self.getFioJob().getTotLats(jobOut) rwRow.append(l) rndMatrix.append(rwRow) return rndMatrix def runRounds(self): ''' Carry out the latency test rounds and check if the steady state is reached. For a maximum of 25 rounds the test loop is carried out. After each test round we check for a measurement window of the last 5 rounds if the steady state has been reached. @return True if the steady state has been reached, False if not. ''' rndMatrix = [] steadyValues = deque([]) xranges = deque([])#Rounds of current measurement window for i in range(StdyState.testRnds): logging.info("#################") logging.info("Round nr. "+str(i)) rndMatrix = self.testRound() self.getRndMatrices().append(rndMatrix) #Latencies always consist of [min,max,mean] latency #Take mean/average for steady state detection steadyValues.append(rndMatrix[-1][-2][2]) xranges.append(i) if i > 4: xranges.popleft() steadyValues.popleft() #check if the steady state has been reached in the last 5 rounds if i >= 4: steadyState = self.getStdyState().checkSteadyState(xranges,steadyValues,i) if steadyState == True: break #Return current steady state return self.getStdyState().isSteady() def run(self): ''' Start the rounds, log the steady state infos. @return True if all tests were run ''' try: self.getDevice().secureErase() except RuntimeError: logging.error("# Could not carry out secure erase for "+self.getDevice().getDevPath()) raise try: if self.__userOptions == None: self.getDevice().precondition(1,1) else: if self.__userOptions.getNj() != None: nj = self.__userOptions.getNj() if self.__userOptions.getIod() != None: iod = self.__userOptions.getIod() self.getDevice().precondition(nj,iod) except RuntimeError: logging.error("# Could not carry out preconditioning for "+self.getDevice().getDevPath()) raise logging.info("########### Starting Latency Test ###########") steadyState = self.runRounds() if steadyState == False: logging.info("# Steady State has not been reached for Latency Test.") self.toLog() return True def toXml(self,root): ''' Get the Xml representation of the test. @param root Name of the new root Xml node @return An xml root element containing the information about the test ''' r = etree.Element(root) # Add Fio version to xml self.getFioJob().appendXml(r) # Add the options to xml self.getOptions().appendXml(r) data = json.dumps(self.__roundMatrices) e = etree.SubElement(r,'roundmat') e.text = data self.getStdyState().appendXml(r) return r def fromXml(self,root): ''' Load and set from an XML representation of a test. @param root Name of root element from which to load values ''' logging.info("########### Loading latency test from "+self.getTestname()+".xml ###########") self.__roundMatrices = json.loads(root.findtext('roundmat')) self.__stdyState.fromXml(root) self.getFioJob().fromXml(root) self.getOptions().fromXml(root) self.toLog() def genPlots(self): ''' Generate plots for latency. ''' import plots.genPlots as pgp pgp.stdyStConvPlt(self,"LAT") pgp.stdyStVerPlt(self,"LAT") pgp.mes2DPlt(self,"avg-LAT") pgp.mes2DPlt(self,"max-LAT") pgp.latMes3DPlt(self)
class SsdIopsTest(DeviceTest): ''' Representing an IOPS test for a ssd based device. ''' ##Labels of block sizes bsLabels = ["1024k","128k","64k","32k","16k","8k","4k","512"] ##Percentages of mixed workloads mixWlds = [100,95,65,50,35,5,0] def __init__(self,testname,device,options=None): ''' Constructor. ''' super(SsdIopsTest,self).__init__(testname,device,options) ## A list of matrices with the collected fio measurement values of each round. self.__roundMatrices = [] self.__stdyState = StdyState() self.getFioJob().addKVArg("rw","randrw") def getRndMatrices(self): return self.__roundMatrices def getStdyState(self): return self.__stdyState def toLog(self): ''' Log information about the steady state and how it has been reached. ''' logging.info("Round matrices: ") logging.info(self.__roundMatrices) self.getStdyState().toLog() def testRound(self): ''' Carry out one IOPS test round. The round consists of two inner loops: one iterating over the percentage of random reads/writes in the mixed workload, the other over different block sizes. @return A matrix containing the sum of average IOPS. ''' jobOut = '' #Fio job output rndMatrix = [] for i in SsdIopsTest.mixWlds: rwRow = [] for j in SsdIopsTest.bsLabels: self.getFioJob().addKVArg("rwmixread",str(i)) self.getFioJob().addKVArg("bs",j) call,jobOut = self.getFioJob().start() if call == False: exit(1) logging.info("mixLoad: " +str(i)) logging.info("bs: "+j) logging.info(jobOut) logging.info("######") rwRow.append(self.getFioJob().getIOPS(jobOut)) rndMatrix.append(rwRow) return rndMatrix def runRounds(self): ''' Carry out the IOPS test rounds and check if the steady state is reached. For a maximum of 25 rounds the test loop is carried out. After each test round we check for a measurement window of the last 5 rounds if the steady state has been reached. @return True if the steady state has been reached, False if not. ''' rndMatrix = [] steadyValues = deque([])#List of 4k random writes IOPS xranges = deque([])#Rounds of current measurement window for i in range(StdyState.testRnds): logging.info("#################") logging.info("Round nr. "+str(i)) rndMatrix = self.testRound() self.getRndMatrices().append(rndMatrix) # Use the last row and its next to last value #-> 0/100% r/w and 4k for steady state detection steadyValues.append(rndMatrix[-1][-2]) xranges.append(i) if i > 4: xranges.popleft() steadyValues.popleft() #check if the steady state has been reached in the last 5 rounds if i >= 4: steadyState = self.getStdyState().checkSteadyState(xranges,steadyValues,i) if steadyState == True: break #Return current steady state return self.getStdyState().isSteady() def run(self): ''' Start the rounds, log the steady state infos. @return True if all tests were run ''' try: self.getDevice().secureErase() except RuntimeError: logging.error("# Could not carry out secure erase for "+self.getDevice().getDevPath()) raise try: if self.getOptions() == None: self.getDevice().precondition(1,1) else: if self.getOptions().getNj() != None: nj = self.getOptions().getNj() if self.getOptions().getIod() != None: iod = self.getOptions().getIod() self.getDevice().precondition(nj,iod) except RuntimeError: logging.error("# Could not carry out preconditioning for "+self.getDevice().getDevPath()) raise logging.info("########### Starting IOPS Test ###########") steadyState = self.runRounds() if steadyState == False: logging.info("# Steady State has not been reached for IOPS Test.") self.toLog() return True def toXml(self,root): ''' Get the Xml representation of the test. @param root Name of the new root Xml node @return An xml root element containing the information about the test ''' r = etree.Element(root) # Add Fio version to xml self.getFioJob().appendXml(r) # Add the options to xml self.getOptions().appendXml(r) data = json.dumps(self.__roundMatrices) e = etree.SubElement(r,'roundmat') e.text = data self.getStdyState().appendXml(r) return r def fromXml(self,root): ''' Load and set from an XML representation of a test. @param root Name of root element from which to load values ''' logging.info("########### Loading IOPS test from "+self.getTestname()+".xml ###########") self.__roundMatrices = json.loads(root.findtext('roundmat')) self.__stdyState.fromXml(root) self.getFioJob().fromXml(root) self.getOptions().fromXml(root) self.toLog() def genPlots(self): ''' Generate plots for IOPS. ''' import plots.genPlots as pgp pgp.stdyStConvPlt(self,"IOPS") pgp.stdyStVerPlt(self,"IOPS") pgp.mes2DPlt(self,"IOPS") pgp.mes3DPlt(self,"IOPS")