[python]代码库
import random
import time
import EnvSetup.EnvSetup
import Library.UFS.TestInstance as TestInstance
# import config.UFS
import os
import copy
import math
import csv
from Library.UFS.ufsDefines import *
from Library.Generic import timer
# Extra Imports
from collections import namedtuple
import collections
class Latency_00_Command_Base(TestInstance.TestInstance):
SIZE_1KB = 1024
SIZE_1MB = 1024 * SIZE_1KB
SIZE_1GB = 1024 * SIZE_1MB
LBA_SIZE = 4 * SIZE_1KB
lbaStepSize = SIZE_1GB / LBA_SIZE
DEBUG = False
vcc = -1
vccq = -1
vccq2 = -1
atariCategory = 'Latency'
atariGroup = 'TSM'
outputUnit = 'ms'
pwrMode = 'Active'
exitOnFailure = False
verbose = False
type = 'Scsi'
def AddCommandArgs(self):
super(Latency_00_Command_Base, self).AddCommandArgs()
# configure divice
self.parser.add_argument('--mediaLunCount', type=int, default=1, help="""configure device with defalut(0ne) lun""")
self.parser.add_argument('--bootLunCount', type=int, default=0, help="""configure device with default(default 0) boot Lun""")
self.parser.add_argument('--competitor', type=bool, default=False, help="""whether the device comes from competitor. defalut False""")
self.parser.add_argument('--tgtProvisionType', type=int, default=3, help="""provisioning type. discard,2,TPRZ=0/erase,3,TPRZ=1""")
# argument for precondition
self.parser.add_argument('--seqTransferTL', type=int, default=0x80, help="""sequential write TL, default 512K""")
self.parser.add_argument('--seqData', type=int, default=0xAA, help="""sequential Write Data""")
self.parser.add_argument('--randNumber', type=int, default=100000, help="""random write cmd count per GB""")
self.parser.add_argument('--randData', type=int, default=0x55, help="""random write data""")
# argument for data collection and flow contorl
self.parser.add_argument('--basicCmdNum', type=int, default=100000, help="""command count for each iteration/GB""")
self.parser.add_argument('--totalCmdNum', type=int, default=100000, help="""Sample points needed for data collection""")
# argument for debug function
# self.parser.add_argument('--specialSaveRawData', type=bool, default=False, help="""For special format save raw data collection""")
self.parser.add_argument('--vuLatencyEn', type=bool, default=False, help="""If using latency VU, should use latency FW. print data profiling debug.""")
self.parser.add_argument('--dumpCache', type=bool, default=False, help="""If necessary, open this. each cache count, script will print command info and vu data""")
self.parser.add_argument('--vuCMDTO', type=float, default=30.0, help="""For read/sync/other command time out parameter. if command > 30ms, timeout""")
self.parser.add_argument('--vuWriteTO', type=float, default=30.0, help="""Just for write, if command > 30ms, timeout""")
self.parser.add_argument('--cacheCount', type=int, default=8, help="""save how many command into cache.""")
# Others
self.parser.add_argument('--defrageTable', type=bool, default=False, help="""dirty card or not""")
def _reconfigDevice(self, bSecureRemovalTypeSet=0, bProvisionTypeReset=3):
if not self.competitor:
self.vuLib.vuCmdtranslate.restoreWriteOnce()
response = self.lun[0].Query.ReadDescriptorSync(0x1, 0, 0, 0x90)
reconfigBuffer = response.DataSegmentBuffer
if reconfigBuffer.GetByte(2) != 0:
reconfigBuffer.SetByte(2, 0)
reconfigBuffer.SetByte(7, bSecureRemovalTypeSet)
self.lun[0].Query.WriteDescriptorSync(0x1, 0, 0, 0x90, reconfigBuffer)
maxAllocUinit = self.lib.query.getdEnhanced1MaxNAllocU()
HighByte = (int(maxAllocUinit) & 0xFF00) >> 8
LowByte = int(maxAllocUinit) & 0xFF
response = self.lun[0].Query.ReadDescriptorSync(1, 0, 0, 0x90)
ReconfigBuf = response.DataSegmentBuffer
for i in range(1, 9):
ReconfigBuf.SetByte(i * 16 + 0xA, bProvisionTypeReset)
ReconfigBuf.SetByte(i * 16, 0)
ReconfigBuf.SetByte(i * 16 + 1, 0)
ReconfigBuf.SetByte(i * 16 + 6, 0)
ReconfigBuf.SetByte(i * 16 + 7, 0)
ReconfigBuf.SetByte(0x16, HighByte)
ReconfigBuf.SetByte(0x17, LowByte)
ReconfigBuf.SetByte(0x10, 1)
ReconfigBuf.SetByte(0x2, 0)
self.lun[0].Query.WriteDescriptorSync(1, 0, 0, 0x90, ReconfigBuf)
def _doBKOPs(self, defautTime=400):
buf = self.mist.Buffer(0x1, LBA_SIZE)
t = timer(defautTime)
while not t.expired:
if self.lib.query.getbBackgroundOpStatus() > 0:
wExceptionEventStatus = self.lib.query.getwExceptionEventStatus()
self.logger.info("send one read command")
self.lun[self.lunID].Read10SimpleSync(0x1, 0x1, buf)
self.logger.info("--------Get wExceptionEventStatus:{}".format(wExceptionEventStatus & 0x4))
time.sleep(60)
else:
break
currentBKOPs = self.lib.query.getbBackgroundOpStatus()
if currentBKOPs == 0 or currentBKOPs == 1:
self.logger.info("current BKOPs has been completed")
else:
self.testFailed('bBackgroundOpStatus is still {} after {}'.format(currentBKOPs, defautTime))
def _newTargetConfg(self, bootOrNot=False):
if not self.competitor:
self.logger.info("########## Create new target configuration descriptor ##########")
if bootOrNot:
bootCapacity = 16
self.lib.lunConfig.createTargetConfig(mediaLunCount=self.mediaLunCount, bootLunCount=self.bootLunCount, setBigLun=True,
useAllCapacity=True, setHighPriorityLun=False,
bProvisioningType=self.tgtProvisionType, bootCapacity_MB=bootCapacity)
else:
self.lib.lunConfig.createTargetConfig(mediaLunCount=self.mediaLunCount, bootLunCount=self.bootLunCount, setBigLun=True,
useAllCapacity=True, setHighPriorityLun=False, bProvisioningType=self.tgtProvisionType)
self.lib.lunConfig.printDescriptor() # Print the new created target descriptor
disabledLun = self.lib.lunConfig.getDisableLunInTargetConfig()
self.logger.info("Disabled LUs are: %s" % disabledLun)
targetCfgOutline = self.lib.lunConfig.getTargetConfigOutline()
for key, value in targetCfgOutline.items():
self.logger.info("Category {} : {}".format(key, value))
# Write the new target configuration descriptor to device
self.lib.lunConfig.writeTargetConfigToDevice()
else:
self.logger.info("the unit comes from competitor")
def _latencyOfPurge(self, purgeTimeOut=None):
"""
Original purgeTimeoOut=4000
Purge all unmaped LBA(s)
NOTE: This latency is in increments of 1ms
:param purgeTimeOut: (int) in seconds the timeout period to wait for the purge command
:return usPurgeTime: (float) command execution time in microseconds (us)
"""
self.logger.info("***********************do purge*********************")
if purgeTimeOut is None:
purgeTimeOut = self.cfg.timeout.purgeTimeout
# Just for leo, to pass this case.
if self.product == "Leo":
purgeTimeOut = 10000
setPurgeResp = self.lib.query.setfPurgeEnable()
if setPurgeResp == 1:
purgeStartTime = time.time()
else:
self.testFailed(
"Set fPurgeEnable flag enable fail, and the fPurgeEnable flag value is {}".format(setPurgeResp))
bPurgeStatus = -1
while bPurgeStatus not in (PURGE_STATUS_STOPPED_BY_HOST, PURGE_STATUS_COMPLETED):
bPurgeStatus = self.lib.query.getbPurgeStatus()
if time.time() - purgeStartTime > purgeTimeOut:
self.testFailed("FAIL bPurgeStatus ({}) not set to {} before timeOut {}".format(setPurgeResp, (
PURGE_STATUS_STOPPED_BY_HOST, PURGE_STATUS_COMPLETED), purgeTimeOut))
purgeEndTime = time.time()
secondsPurgeTime = purgeEndTime - purgeStartTime
usPurgeTime = self.lib.generic.changeUnits("us", "seconds", secondsPurgeTime)
return usPurgeTime
def _eraseFullCardPost(self):
self.logger.info("pre/post condition: format unit and purge")
lunList = self.lib.reportLuns.getAvailableNormalLuns()
for lunID in lunList:
self.lun[lunID].FormatUnitSimpleSync()
self._latencyOfPurge()
def _defragTableVB(self):
tl = 1
buf = self.mist.Buffer(1, 8)
maxLba = self.lun[self.lunID].ReadCapacity10Sync(buf).MaxLba
writeBuffer = self.mist.Buffer(tl, LBA_SIZE)
writeBuffer.Fill(0x55)
for i in range(12):
startLba = random.randint(0, 1020)
while startLba < maxLba:
if startLba + tl > maxLba:
startLba = maxLba - tl
self.lun[self.lunID].Write10Sync(lba=startLba, count=tl, disablePageOut=False, fua=False, fuaNv=False, buf=writeBuffer)
startLba = startLba + 1024
def _sendWriteCMD(self, startLba, endLba, transferLen=1, writeData=0xAA, cmdNumber=0, seq=False, QD=32):
outstandingCmd = {}
responseList = []
timeout = 60
buffers = [self.mist.Buffer(transferLen, LBA_SIZE) for _ in range(QD)]
buffTrk = range(QD)
temp = 0
if seq:
self.logger.debug("sequential write from startLba=--{}-- to endLba=--{}--".format(startLba, endLba))
while (startLba <= endLba):
if startLba + transferLen > endLba:
tempTL = endLba - startLba + 1
else:
tempTL = transferLen
if len(outstandingCmd) < QD:
buffNum = buffTrk.pop()
buf = buffers[buffNum]
buf.Fill(writeData)
usr = self.lun[self.lunID].Write10Simple(startLba, tempTL, buf)
outstandingCmd[usr.SequenceId] = (buffNum)
if len(outstandingCmd) == QD:
startTime = time.time()
while len(responseList) == 0:
elapsedTime = time.time() - startTime
if elapsedTime > timeout:
break
try:
responseList = self.lun[self.lunID].CompletedResponses
except self.mist.ufs.UpiuCommandError as e:
self.testFailed("UpiuCommandError happened {}".format(e))
except Exception as e:
self.testFailed("Exception happened {}".format(e))
for resp in responseList:
sequenceId = resp.SequenceId
buffNum = outstandingCmd.pop(sequenceId)
buffTrk.append(buffNum)
responseList = []
startLba += tempTL
if startLba == endLba + 1:
if 0 < len(outstandingCmd) < QD:
for i in range(len(outstandingCmd)):
self.lun[self.lunID].WaitForOneResponse()
else:
if cmdNumber:
self.logger.debug("random send cmdNumber={} write command in startLba={},endLba={}".format(cmdNumber, startLba, endLba))
while (temp < cmdNumber):
if len(outstandingCmd) < QD:
buffNum = buffTrk.pop()
buf = buffers[buffNum]
buf.Fill(writeData)
tempLba = random.randint(startLba, endLba - transferLen + 1)
usr = self.lun[self.lunID].Write10Simple(tempLba, transferLen, buf)
temp = temp + 1
outstandingCmd[usr.SequenceId] = (buffNum)
if len(outstandingCmd) == QD:
startTime = time.time()
while len(responseList) == 0:
elapsedTime = time.time() - startTime
if (elapsedTime > timeout) and len(responseList) == 0:
self.testFailed("Timeout occurred after %s,no responses returned " % elapsedTime)
break
try:
responseList = self.lun[self.lunID].CompletedResponses
except self.mist.ufs.UpiuCommandError as e:
self.testFailed("UpiuCommandError happened {}".format(e))
except Exception as e:
self.testFailed("Exception happened {}".format(e))
for resp in responseList:
sequenceId = resp.SequenceId
buffNum = outstandingCmd.pop(sequenceId)
buffTrk.append(buffNum)
responseList = []
if temp == cmdNumber:
for i in range(len(outstandingCmd)):
self.lun[self.lunID].WaitForOneResponse()
else:
writeBuffer = self.mist.Buffer(transferLen, LBA_SIZE)
writeBuffer.Fill(writeData)
self.logger.debug("random send write command on current lbaRange until all LBA has been written")
self.lib.writeReadAsync.writeRandom(self.lunID, "Write10", writeBuffer, startLba, endLba, transferLen, QD, fua=True)
def _overwriteCli(self):
self.responseLoggerIsEnabled = False
self.responseLoggerReportUpiu = False
self.responseLoggerReportFailOnly = True
self.needstandardTestStart = False
def _preConditionForSAS(self, SSPreCondition=False):
if self.DEBUG:
self.logger.info('DEBUG running, precondition skipped')
return
self.logger.info("sequential write full card with ChunkSize *** 512KB ***, data is 0xAA")
buff = self.mist.Buffer(1, 8)
endLba = self.lun[self.lunID].ReadCapacity10Sync(buff).MaxLba
self._sendWriteCMD(0, endLba, transferLen=self.seqTransferTL, seq=True)
if not SSPreCondition:
self.logger.info("============Random write 100000 per GB with pattern 0x55============")
for startLba, endLba in self.LbaRange:
self._sendWriteCMD(startLba, endLba, writeData=self.randData, cmdNumber=self.randNumber)
else:
self.logger.info("precondition for SS's test method")
cmdNumber = self.maxLba / self.seqTransferTL
self._sendWriteCMD(0, self.maxLba, transferLen=self.seqTransferTL, writeData=self.randData, cmdNumber=cmdNumber)
if self.defrageTable:
self._defragTableVB()
def _preCondition(self, lunID, loopSize=1000):
"""
Precondition options you can overwrite by children classes.
:param lunID: current lun
:return oldValues: (dict) the values before this method changed them
:return avgTeUnRe: (float) average test unit ready time
:return secIdleBoundary: (float) time to put device in idle mode in seconds
"""
newValues = {}
if hasattr(self, 'newWce') and self.newWce >= 0:
newValues["newWce"] = self.newWce
if hasattr(self, 'newRcd') and self.newRcd >= 0:
newValues["newRcd"] = self.newRcd
if hasattr(self, 'gearHS') and self.gearHS >= 0:
newValues["gearHS"] = self.gearHS
if hasattr(self, 'rateHS') and self.rateHS != "None":
newValues["rateHS"] = self.rateHS
if hasattr(self, 'ufsPwrMode') and self.powerMode >= 0:
newValues["ufsPwrMode"] = self.ufsPwrMode
if hasattr(self, 'laneNum') and self.laneNum >= 0:
newValues["laneNum"] = self.laneNum
if hasattr(self, 'bDataReliability') and self.bDataReliability >= 0:
newValues["bDataReliability"] = self.bDataReliability
newValues["newVoltages"] = self.lib.performanceAdHoc.getVoltages(
vcc=self.vcc, vccq=self.vccq, vccq2=self.vccq2)
oldValues = self.lib.performanceAdHoc.latencyPreCondition(lunID=lunID, newValues=dict(newValues), verbose=False,
exitOnFailure=self.exitOnFailure)
self.logger.parameter(paramName="newValues", value=newValues, category=self.atariCategory, group=self.atariGroup)
self.logger.parameter(paramName="oldValues", value=oldValues, category=self.atariCategory, group=self.atariGroup)
(usAvgTeUnRe, _, _) = self.lib.performanceAdHoc.testUnitReadyLoopAndPrint(lunID=lunID, loopSize=loopSize, verbose=False)
avgTeUnRe = self.lib.generic.changeUnits(self.outputUnit, "us", usAvgTeUnRe)
self.logger.parameter(paramName="Test Unit Ready Average", value=avgTeUnRe, unit=self.outputUnit, category=self.atariCategory, group=self.atariGroup)
if self.pwrMode == "Idle":
(_, rawBoundary, rawUnit) = self.cfg.latency.getLatencyExpected("Typical", "Active to Idle")
idleBoundary = self.lib.generic.changeUnits(self.outputUnit, rawUnit, rawBoundary)
else:
idleBoundary = None
preCondition = namedtuple("preCondition", "oldValues avgTeUnRe secIdleBoundary")
return preCondition(oldValues=oldValues, avgTeUnRe=avgTeUnRe, secIdleBoundary=idleBoundary)
def _dumpCacheData(self):
self.logger.info("===================Dump CMD/VU Buffer=======================")
self.logger.info("NOTE: CMD Info Format: (cmdType, lun, lba, transferLen, taskTag, sequenceId, exec(ms)")
self.logger.info("Debug. cache cmd count:{}".format(len(self.vuCacheDict)))
for cmdKey, vuValue in self.vuCacheDict.items():
tempList = []
tempList.append(cmdKey)
self.logger.info("cmdKey(ms):{}".format(cmdKey))
self.logger.info("vuValue:{}".format(vuValue))
for index, tempValue in enumerate(vuValue):
tempList.append(tempValue)
self._saveRawData(["TimeOut_VU_Get_Latency"], [tempList])
# if the whole cache data are dumped, clear cache.
self.vuCacheDict.clear()
def _vuLatency(self, cmdInfo, checkTO=True):
# cmdInfo = (cmdType, lun, lba, transferLen, taskTag, sequenceId, execTime)
cmdType = cmdInfo[0]
execTime = cmdInfo[-1]
if self.cacheCount:
if len(self.vuCacheDict) >= self.cacheCount:
if self.dumpCache:
self._dumpCacheData()
else:
# if no dump data, then pop one item for the next cmd info.
self.vuCacheDict.popitem(0)
vuData = self.vuLib.vuCmdtranslate.getProfileDataLatency()
self.vuCacheDict[cmdInfo] = vuData
# Check command whether timeout.if yes, test failed immediately.
if cmdType == 'Mode Sense':
self.vuLatencyTO = 1
if cmdType == "Mode Select":
self.vuLatencyTO = 100
self.logger.info("111----set command timeout {}ms for cmdType {}".format(self.vuLatencyTO, cmdType))
if checkTO and execTime >= self.vuLatencyTO:
if self.cacheCount:
self._dumpCacheData()
try:
vuData = self.vuLib.vuCmdtranslate.getProfileDataLatency()
self.logger.info("Oops! Occurred cmd time out!, TargetTO:{} ms".format(self.vuLatencyTO))
self.logger.info("NOTE: CMD Info Format: (cmdType, lun, lba, transferLen, taskTag, sequenceId, exec(ms)")
self.logger.info("CMD Info(ms):{}, ".format(cmdInfo))
self.testFailed("GetProfileData:{}".format(vuData))
except self.mist.ufs.UpiuCommandError as e:
self.logger.info("Get profileData error:{}".format(e))
def _postCondition(self, lunID, oldValues):
"""
Postcondition options you can overwrite by children classes.
:param lunID: current lun
:param oldValues: (dict) the values to set the device back to before ending the next test
"""
self.lib.performanceAdHoc.latencyPostCondition(lunID=lunID, oldValues=oldValues)
def _afterLoopBeforeAveraging(self, usLatencies):
"""
Some scripts need to modify the latencies before proceeding with the test
:param lunID: (int) current lun
:param usLatencies: [int] The latencies from the main function in micro seconds
:returns latencies: [int] The modified latencies
"""
latencies = self.lib.generic.changeUnits(self.outputUnit, "us", usLatencies)
return latencies
def _splitdrive(self, p):
"""Split a pathname into drive and path specifiers. Returns a 2-tuple
"(drive,path)"; either part may be empty"""
if p[1:2] == ':':
return p[0:2], p[2:]
return '', p
def split(self, p):
"""Split a pathname.
Return tuple (head, tail) where tail is everything after the final slash.
Either part may be empty."""
d, p = self._splitdrive(p)
# set i to index beyond p's last slash
i = len(p)
while i and p[i - 1] not in '/\\':
i = i - 1
head, tail = p[:i], p[i:] # now tail has no slashes
# remove trailing slashes from head, unless it's all slashes
head2 = head
while head2 and head2[-1] in '/\\':
head2 = head2[:-1]
head = head2 or head
return d + head, tail
def _openNewFile(self, fName):
# arg maybe include new csv file
if fName:
tempCsv = fName + "_Latencies_data.csv"
else:
tempCsv = "Command_Latencies_data.csv"
if self.logFilePath.endswith('.log'):
subPath2, _ = self.split(self.logFilePath)
subPath1, _ = self.split(subPath2)
filePath, _ = self.split(subPath1)
else:
filePath = self.logFilePath
fileName = os.path.join(filePath, tempCsv)
if os.path.exists(fileName):
self.logger.info("-------file exist--------")
return fileName
def _calSTD(self, sortedRawList=None, avgTime=0):
n = len(sortedRawList)
if n == 1:
return 0
tempList = [pow((item - avgTime), 2) for item in sortedRawList]
stdDeviation = math.sqrt(sum(tempList) / float(n - 1))
return stdDeviation
def classOfNines(self, data, outliers=100):
"""
For quality of service (QoS) we usually need to print not only the maximum but also the 99% largest element
:param data: All data points collected, probably latencies
:type data: list
:param outliers: Have at least this many outliers before calculating that class of nines
:type outliers: int
:return results: The class of nines results
:rtype results: dict
Example
results = classOfNines(range(1, 10000000+1))
print [(key, results[key]) for key in sorted(results.keys())]
"""
data.sort()
results = {}
nines = [0.99, 0.999, 0.9999, 0.99999, 0.999999, 0.9999999, 0.99999999, 0.999999999, 0.9999999999]
n = 0
listLen = len(data)
while True:
if not listLen / 10 ** (n + 2) >= outliers:
break
index = int(nines[n] * listLen) - 1
results[nines[n]] = data[index]
n += 1
return results
def _calAllData(self, cmdType, cmdName, rawData, sampleNumber=None):
"""
Statistics of raw latency data
:param cmdType: Category of the operation, eg, QoS, SCSI, UPIU
:param cmdName: Details of the cmd, eg, 4K read dirty
:param rawData: raw latency data
:param sampleNumber: the count of data points collected
:return: statistics data list, eg, [['QoS', '4K read dirty', 'Min', 20], ['QoS', '4K read dirty', 'Max', 30]...]
"""
rawDataList = copy.deepcopy(rawData)
if not sampleNumber:
sampleNumber = len(rawData)
rawDataList.sort()
if len(rawDataList) == 1:
avgTime = rawDataList[0]
maxTime = rawDataList[0]
minTime = rawDataList[0]
median = rawDataList[0]
stdDeviation = 0 # standard deviation
else:
avgTime = float(sum(rawDataList)) / len(rawDataList)
maxTime = max(rawDataList)
minTime = min(rawDataList)
sortedTimes = sorted(rawDataList)
if (len(sortedTimes) == 0):
median = 0
else:
if (len(sortedTimes) % 2) == 1:
median = sortedTimes[len(sortedTimes) / 2]
else:
median = (sortedTimes[(len(sortedTimes) / 2) - 1] + sortedTimes[(len(sortedTimes) / 2)]) / 2
stdDeviation = self._calSTD(rawDataList, avgTime)
keys = []
values = []
countNum = 0
nines = self.classOfNines(rawDataList)
nines1 = sorted(nines.iteritems(), key=lambda d: d[1], reverse=False)
if len(rawDataList) < 10000:
values = ["NA", "NA", "NA"]
else:
for key, value in nines1:
keys.append(key)
values.append(value)
countNum = countNum + 1
if countNum == 3:
break
if len(keys) == 1:
keys.extend(["NA","NA"])
values.extend(["NA","NA"])
if len(keys) == 2:
keys.append("NA")
values.append("NA")
allData = [
[cmdType] + [cmdName] + ['Min'] + [minTime],
[cmdType] + [cmdName] + ['Avg'] + [avgTime],
[cmdType] + [cmdName] + ['Median'] + [median],
[cmdType] + [cmdName] + ['Std Dev'] + [stdDeviation],
[cmdType] + [cmdName] + ['99%'] + [values[0]],
[cmdType] + [cmdName] + ['99.9%'] + [values[1]],
[cmdType] + [cmdName] + ['99.99%'] + [values[2]],
[cmdType] + [cmdName] + ['Max'] + [maxTime],
[cmdType] + [cmdName] + ['sampleNumber'] + [sampleNumber]
]
# allData = [cmdType] + [CMD] + [minTime, avgTime, median, stdDeviation] + values + [maxTime, sampleNumber]
self.logger.info("-----------------------------------------------------------------------------------------------------------")
self.logger.info("{:<16} {:<48} {:<8} {:<16} {:<8} {:<16} {:<8} {:<8} {:<8} {:<8} {:<8}".
format("cmdType", "CMD", "MinTime", "AVERAGE", "Median", "STD", "99%", "99.9%", "99.99%",
"MaxTime", "sampleNumber"))
self.logger.info("{:<16} {:<48} {:<8} {:<16} {:<8} {:<16} {:<8} {:<8} {:<8} {:<8} {:<8}".
format(cmdType, cmdName, minTime, avgTime, median, stdDeviation, values[0],
values[1], values[2], maxTime, sampleNumber))
self.logger.info("------------------------------------------------------------------------------------------------------------")
return allData
def _handleLatencies(self, allData, fName=None):
# allData---type: list or int(no raw data)
# file name---type str without(.csv):new csv file default:
fileName = self._openNewFile(fName)
wrFileHdlr = open(fileName, "ab+")
wt = csv.writer(wrFileHdlr)
for i in xrange(len(allData)):
data = allData[i]
wt.writerow(data)
wrFileHdlr.close()
def _saveRawData(self, nameList, rawDataList):
"""
Save raw latency data to csv file
:param nameList: a list which contains the cm names, used in csv file naming
:param rawDataList: raw data corresponding to nameList
:return: None
"""
for i in range(len(nameList)):
if self.logFilePath.endswith('.log'):
rawDataFile = self.logFilePath.rstrip('.log') + "_" + nameList[i] + "_raw_data.csv"
else:
rawDataFile = self.logFilePath + "/" + self.logFileName[:-4] + "_" + nameList[i] + "_raw_data.csv"
wrFileHdlr = open(rawDataFile, "a+")
for execTime in rawDataList[i]:
wrFileHdlr.write("{}\n".format(execTime))
wrFileHdlr.close()
def _rawDataFileName(self, name):
"""
Get target raw data file, related to func _saveRawData()
:param name: cmd name
:return: absolute raw data file path
"""
if self.logFilePath.endswith('.log'):
rawDataFile = self.logFilePath.rstrip('.log') + "_" + name + "_raw_data.csv"
else:
rawDataFile = self.logFilePath + "/" + self.logFileName[:-4] + "_" + name + "_raw_data.csv"
return rawDataFile
def _nandTemperaturePrint(self):
"""Print the current NAND temperature in Celsius
"""
temp = self.lib.vuHighLevelLib.getNandTemperature()
self.logger.info(temp)
def _generateCommandIndex(self, startLba=0, endLba=0, chunkSize=1, randCount=100000, percentage=50):
# random address list without overlap
def randrange(start, end, size, randCount):
if ((end - start) < (size - 1)) or (len(lbaList) == randCount):
return 0
lba = random.randint(start, end - size + 1)
lbaList.append(lba)
randrange(start, lba - 1, size, randCount)
randrange(lba + size, end, size, randCount)
# Make sure keep more than 50% UDA after unmap. if necessary, should rerun the test to collect 100,000
UDAPerct = (endLba - startLba + 1) * percentage / 100
gpNum = UDAPerct / chunkSize
sampleCnt = gpNum if gpNum < randCount else randCount
if chunkSize == 1:
cmdIndex = [[tempLba, tempLba + chunkSize - 1] for tempLba in
random.sample(xrange(startLba, endLba + 1 - chunkSize + 1), sampleCnt)]
else:
lbaList = []
randrange(startLba, endLba, chunkSize, randCount)
cmdIndex = [[tempLba, tempLba + chunkSize - 1] for tempLba in random.sample(lbaList, sampleCnt)]
return cmdIndex
def _getUnmapTimeQD(self, unmapCMDIndex=None, unmapSize=0x1, queueDepth=8):
responseList = []
unmapLatencies = []
outstandingCmd = {}
outstandingCmdTotalCnt = 0
while (unmapCMDIndex):
if (len(outstandingCmd) < queueDepth):
currentCmd = unmapCMDIndex.pop(0)
startLba = currentCmd[0]
usr = self.lun[self.lunID].UnmapSimple(startLba, unmapSize)
outstandingCmdTotalCnt += 1
outstandingCmd[usr.SequenceId] = ('Unmap', 0, currentCmd[0], unmapSize)
else:
t = timer(30)
while (not t.expired) and (len(responseList) == 0):
try:
responseList = self.lun[self.lunID].CompletedResponses
except Exception as e:
self.testFailed("Exception occurred: %s" % e)
if t.expired:
self.testFailed("Timeout occurred after %s,no responses returned " % t)
for resp in responseList:
execTime = float(resp.ExecTime * 10 ** -3)
sequenceId = resp.SequenceId
unmapLatencies.append(execTime)
outstandingCmd.pop(sequenceId)
# cmdType, buffNum, randLba, tranfLen = outstandingCmd.pop(sequenceId)
# # For fw request, add vu to get command's ingo
# if self.vuLatencyEn and not self.competitor:
# cmdInfo = (cmdType, self.lunID, randLba, tranfLen, resp.TaskTag, sequenceId, execTime)
# self._vuLatency(cmdInfo)
responseList = []
while len(outstandingCmd):
try:
responseList = self.lun[self.lunID].WaitForAllResponses()
except Exception as e:
self.testFailed("Exception occurred: %s" % e)
for resp in responseList:
execTime = float(resp.ExecTime * 10 ** -3)
sequenceId = resp.SequenceId
unmapLatencies.append(execTime)
cmdType, buffNum, randLba, tranfLen = outstandingCmd.pop(sequenceId)
# For fw request, add vu to get command's info
# if self.vuLatencyEn and not self.competitor:
# cmdInfo = (cmdType, self.lunID, randLba, tranfLen, resp.TaskTag, sequenceId, execTime)
# self._vuLatency(cmdInfo)
#
# # If dump the remaining cache data.
# if self.vuLatencyEn and not self.competitor and self.dumpCache and len(self.vuCacheDict):
# self.logger.info("The last vcCacheDice length:{}".format(len(self.vuCacheDict)))
# self._dumpCacheData()
return unmapLatencies
def _collectUnmapLatencies(self, unmapSize=0x1, QD=8, totalCnt=100000, maxUnmapPert=100):
unmapLatenciesList = []
unmapCMDIndex = self._generateCommandIndex(0, self.maxLba, chunkSize=unmapSize, randCount=totalCnt,
percentage=maxUnmapPert)
unmapLatenciesList.extend(self._getUnmapTimeQD(unmapCMDIndex, unmapSize, QD))
while (len(unmapLatenciesList) < totalCnt):
self.logger.info('{} sampling points collected, switch to next iteration'.format(len(unmapLatenciesList)))
self._preConditionForSAS()
unmapCMDIndex = self._generateCommandIndex(0, self.maxLba, chunkSize=unmapSize,
randCount=(totalCnt - len(unmapLatenciesList)))
unmapLatenciesList.extend(self._getUnmapTimeQD(unmapCMDIndex, unmapSize, QD))
return unmapLatenciesList
def _getVariables(self, lunID):
"""
Return the variable needed for this script to run. This method is overwritten by children classes.
:param lunID: (int) Current LUN
:returns cmdCalls ([functions]) The commands that the latencies are to be taken from
:returns cmdNames ([str]) Names of the commands in cmdCalls. Set to None if you don't want latencies from that command.
:returns isSequential (bool) When looping through should commands be run in order like 111122223333 (True) or 123123123123 (False)
"""
def buffer_():
return self.mist.Buffer(sectorCount=1, bytesPerSector=LBA_SIZE)
def inquiry():
return self.lun[lunID].InquirySync(enableVitalProductData=True, pageCode=0, buf=buffer_())
cmdCalls = [inquiry]
cmdNames = ["Inquiry"]
isSequential = True
getVariables = namedtuple("getVariables", "cmdCalls cmdNames isSequential")
return getVariables(cmdCalls=cmdCalls, cmdNames=cmdNames, isSequential=isSequential)
def _enterAndExitH8(self, delay=0):
H8_Exit_lat = []
respHibern8Enter = self.lib.dme.hibernateEnter()
if (respHibern8Enter != 0):
self.addFailure("Hibern8 enter failed. status is {} ".format(respHibern8Enter))
self.logger.info('Step2.1-----Wait 5s, and monitor Iccq2---')
time.sleep(delay * 1.0 / 1000)
# self.lib.powerMeasurement.measureVccCurrent(1000, delay=1)
if delay == 0:
one_million_samples = 1 * 1000 * 1000
self.lib.powerMeasurement.measureVccqVccq2Current(samples=2 * one_million_samples, sampleRate=250, test="Idle",
temperature="25C", hibernate=True)
self.logger.info("Step2.2-----Exit hibernate -------")
response = self.lun[self.lun.keys()[0]].Dme.HibernateExit()
if ((response.Argument2 & 0xFF) != 0):
self.addFailure("Hibern8 Exit DME command failed. error code is {} ".format(response.Argument2))
else:
self.logger.info("exec time of exit hibernate is {}us".format(response.ExecTime))
H8_Exit_lat.append(response.ExecTime)
def getBigLunId(self):
lunList = self.lib.reportLuns.getAvailableNormalLuns()
bigLun = 0
maxLbaBigLun = 0
for lunId in lunList:
buf = self.mist.Buffer(1, 8)
tempLba = self.lun[lunId].ReadCapacity10Sync(buf).MaxLba
if tempLba > maxLbaBigLun:
bigLun = lunId
maxLbaBigLun = tempLba
maxUnmapLbaSize = self.lib.unmapAsync._getMaxUnmapLbaSize(bigLun)
intCapacityGB = maxLbaBigLun / self.lbaStepSize
maxLba = intCapacityGB * self.lbaStepSize
lbaMainStart = 0
LbaRange = [(startLba, endLba) for startLba, endLba in
zip(range(lbaMainStart, maxLba - self.lbaStepSize, self.lbaStepSize), range(lbaMainStart + self.lbaStepSize - 1, maxLba, self.lbaStepSize))]
return bigLun, maxLbaBigLun, LbaRange, maxUnmapLbaSize
def getLatencies(self, cmdCalls, isSequential, secIdleBoundary):
usLatencies = self.lib.performanceAdHoc.loopCmd(
command=cmdCalls, loopSize=self.totalCmdNum, sequential=isSequential, idleSleep=secIdleBoundary, verbose=self.verbose)
return usLatencies
def Test(self):
"""
This is the main test function of the TC Script.
"""
self._eraseFullCardPost()
self.logger.info("<Step1> PRECONDITION: Lun config")
self._newTargetConfg()
self.lunID, self.maxLba, self.LbaRange, self.maxUnmapLbaSize = self.getBigLunId()
self.vuCacheDict = collections.OrderedDict()
self.vuLatencyTO = self.vuCMDTO
self.logger.info("Lun {}".format(self.lunID))
# ####### VARIABLES ####### #
cmdCalls, cmdNames, isSequential = self._getVariables(self.lunID)
self.cmdNames = cmdNames
# ####### PRECONDITION ####### #
self.logger.info("<Step2> Send 1000 * TUR to measure host overhead ")
oldValues, avgTeUnRe, idleBoundary = self._preCondition(lunID=self.lunID)
secIdleBoundary = self.lib.generic.changeUnits("seconds", self.outputUnit, idleBoundary)
# ####### MAIN ####### #
self.logger.info("<Step3> Send {} * {} commands to measure latency".format(self.totalCmdNum, cmdNames))
usLatencies = self.getLatencies(cmdCalls, isSequential, secIdleBoundary)
latencies = self._afterLoopBeforeAveraging(usLatencies=usLatencies)
self._saveRawData(self.cmdNames, latencies)
# make sure to use len(latencies) in case of duplicated cmdNames
for i in xrange(len(latencies)):
allData = self._calAllData(self.type, cmdNames[i], latencies[i])
self._handleLatencies(allData, self.logFileName[:-4])
self.logger.debug("POSTCONDITION")
self._postCondition(lunID=self.lunID, oldValues=oldValues)
self._eraseFullCardPost()
def Main():
test = Latency_00_Command_Base()
exit(test.Run())
if __name__ == "__main__":
Main()
[源代码打包下载]
中级程序员
by: 小鬼哈哈哈 发表于:2020-02-25 16:34:30 顶(0) | 踩(0) 回复
这个是干嘛的?
回复评论