From d63ccffe54b50e20df12320594be7722a130a55d Mon Sep 17 00:00:00 2001 From: "guangshui.li" Date: Tue, 30 Aug 2022 17:50:12 -0400 Subject: [PATCH 1/4] iosdiag: Fix bug reported by script 'iosdiag_data_analysis' once analyze the result of iohang Signed-off-by: guangshui.li --- .../combine/iosdiag/data_analysis/iosdiag_data_analysis.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/tools/combine/iosdiag/data_analysis/iosdiag_data_analysis.py b/source/tools/combine/iosdiag/data_analysis/iosdiag_data_analysis.py index 1a3cc36e..716a157a 100644 --- a/source/tools/combine/iosdiag/data_analysis/iosdiag_data_analysis.py +++ b/source/tools/combine/iosdiag/data_analysis/iosdiag_data_analysis.py @@ -264,8 +264,11 @@ class hangAnalysis(): totalIosDicts[disk] += 1 statDict = statDicts['summary'][diskIdx] abnormalList = sDict['abnormal'].split() - hungComponentIdx = components.index(abnormalList[0].split('(')[0]) - hungDelay = long(abnormalList[-2]) + component = abnormalList[0].split('(')[0] + if component not in components: + return + hungComponentIdx = components.index(component) + hungDelay = float(abnormalList[-2]) statDict['hung ios'][hungComponentIdx]['count'] += 1 maxHungDelay = statDict['hung ios'][hungComponentIdx]['max'] minHungDelay = statDict['hung ios'][hungComponentIdx]['min'] -- Gitee From 3c3f3f3ac0e3a3a592e02709b97365db5ae65d5b Mon Sep 17 00:00:00 2001 From: "guangshui.li" Date: Wed, 31 Aug 2022 10:19:44 +0800 Subject: [PATCH 2/4] iofsstat: Add misc mode Signed-off-by: guangshui.li --- .../tools/detect/io/iofsstat/diskstatClass.py | 127 +++++---- .../tools/detect/io/iofsstat/fsstatClass.py | 251 ++++++++---------- source/tools/detect/io/iofsstat/iofsstat.py | 62 +++-- .../tools/detect/io/iofsstat/iostatClass.py | 130 ++++----- .../tools/detect/io/iofsstat/promiscClass.py | 193 ++++++++++++++ 5 files changed, 482 insertions(+), 281 deletions(-) mode change 100644 => 100755 source/tools/detect/io/iofsstat/diskstatClass.py mode change 100644 => 100755 source/tools/detect/io/iofsstat/fsstatClass.py mode change 100644 => 100755 source/tools/detect/io/iofsstat/iofsstat.py mode change 100644 => 100755 source/tools/detect/io/iofsstat/iostatClass.py create mode 100755 source/tools/detect/io/iofsstat/promiscClass.py diff --git a/source/tools/detect/io/iofsstat/diskstatClass.py b/source/tools/detect/io/iofsstat/diskstatClass.py old mode 100644 new mode 100755 index 4e0ad2ad..5a9d0865 --- a/source/tools/detect/io/iofsstat/diskstatClass.py +++ b/source/tools/detect/io/iofsstat/diskstatClass.py @@ -34,29 +34,46 @@ def humConvert(value, withUnit): class diskstatClass(object): - def __init__(self, devname, utilThresh, cycle, json): + def __init__(self, devname, utilThresh, json, nodiskStat): self.devname = devname self.json = json + self.cycle = 1 + self.started = False + self.nodiskStat = nodiskStat self.utilThresh = int(utilThresh) if utilThresh is not None else 0 - self.cycle = int(cycle) if cycle > 0 else 1 self.fieldDicts = OrderedDict() self.diskInfoDicts = {} self.deviceStatDicts = {} self.f = open("/proc/diskstats") + if json: + self.fJson = open(json, 'w+') def getDevNameByDevt(self, devt): return self.diskInfoDicts[str(devt)] + def getMasterDev(self, dev): + for devt, disk in self.diskInfoDicts.items(): + if os.path.exists('/sys/block/'+disk) and disk in dev: + return disk + return None + + def getDiskStatInd(self, disk, key): + self.deviceStatDicts[disk][key] + def start(self): fieldDicts = self.fieldDicts diskInfoDicts = self.diskInfoDicts deviceStatDicts = self.deviceStatDicts + if self.started: + return + self.started = True + self.cycle = time.time() self.f.seek(0) for stat in self.f.readlines(): stat = stat.split() if self.devname is not None and self.devname not in stat[2] and \ - stat[2] not in self.devname: + stat[2] not in self.devname: continue field = { @@ -80,116 +97,122 @@ class diskstatClass(object): def stop(self): fieldDicts = self.fieldDicts deviceStatDicts = self.deviceStatDicts - secs = self.cycle + self.cycle = max(int(time.time()-self.cycle), 1) + + if not self.started: + return + self.started = False self.f.seek(0) for stat in self.f.readlines(): stat = stat.split() if self.devname is not None and self.devname not in stat[2] and \ - stat[2] not in self.devname: + stat[2] not in self.devname: continue - for idx, value in fieldDicts[stat[2]].items(): + for idx,value in fieldDicts[stat[2]].items(): value[1] = long(stat[int(idx)+2]) - for devname, field in fieldDicts.items(): + for devname,field in fieldDicts.items(): if self.devname is not None and devname != self.devname: continue - util = round((field['10'][1]-field['10'][0])*100.0/(secs*1000), 2) + util = round((field['10'][1]-field['10'][0])*100.0/(self.cycle*1000),2) util = util if util <= 100 else 100.0 if util < self.utilThresh: continue deviceStatDicts[devname]['util%'] = util - r_iops = round((field['1'][1]-field['1'][0]) / secs, 1) + r_iops = field['1'][1]-field['1'][0] deviceStatDicts[devname]['r_iops'] = r_iops - w_iops = round((field['5'][1]-field['5'][0]) / secs, 1) + w_iops = field['5'][1]-field['5'][0] deviceStatDicts[devname]['w_iops'] = w_iops - r_bps = (field['3'][1]-field['3'][0]) / secs * 512 + r_bps = (field['3'][1]-field['3'][0]) * 512 deviceStatDicts[devname]['r_bps'] = r_bps - w_bps = (field['7'][1]-field['7'][0]) / secs * 512 + w_bps = (field['7'][1]-field['7'][0]) * 512 deviceStatDicts[devname]['w_bps'] = w_bps r_ticks = field['4'][1]-field['4'][0] w_ticks = field['8'][1]-field['8'][0] - wait = round((r_ticks+w_ticks)/(r_iops+w_iops), - 2) if (r_iops+w_iops) else 0 + wait = round((r_ticks+w_ticks)/(r_iops+w_iops), 2) if (r_iops+w_iops) else 0 deviceStatDicts[devname]['wait'] = wait - r_wait = round(r_ticks / r_iops, 2) if r_iops else 0 + r_wait = round(r_ticks / r_iops, 2) if r_iops else 0 deviceStatDicts[devname]['r_wait'] = r_wait - w_wait = round(w_ticks / w_iops, 2) if w_iops else 0 + w_wait = round(w_ticks / w_iops, 2) if w_iops else 0 deviceStatDicts[devname]['w_wait'] = w_wait + def __showJson(self): deviceStatDicts = self.deviceStatDicts - + statJsonStr = '{\ - "time":"",\ - "diskstats":[]}' + "time":"",\ + "diskstats":[]}' dstatDicts = json.loads(statJsonStr, object_pairs_hook=OrderedDict) - dstatDicts['time'] = time.strftime( - '%Y/%m/%d %H:%M:%S', time.localtime()) - for devname, stat in deviceStatDicts.items(): - if self.deviceStatDicts[devname]['util%'] < 0: + dstatDicts['time'] = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime()) + for devname,stat in deviceStatDicts.items(): + if stat['util%'] < 0: continue dstatJsonStr = '{\ - "diskname":"",\ - "r_iops":0,\ - "w_iops":0,\ - "r_bps":0,\ - "w_bps":0,\ - "wait":0,\ - "r_wait":0,\ - "w_wait":0,\ - "util%":0}' + "diskname":"","r_iops":0,"w_iops":0,"r_bps":0,"w_bps":0,\ + "wait":0,"r_wait":0,"w_wait":0,"util%":0}' dstatDict = json.loads(dstatJsonStr, object_pairs_hook=OrderedDict) dstatDict["diskname"] = devname - for key, val in stat.items(): + for key,val in stat.items(): dstatDict[key] = val dstatDicts["diskstats"].append(dstatDict) if len(dstatDicts["diskstats"]) > 0: - print(json.dumps(dstatDicts)) + data = json.dumps(dstatDicts) + self.writeDataToJson(data) return def show(self): + secs = self.cycle deviceStatDicts = self.deviceStatDicts + if self.nodiskStat: + return if self.enableJsonShow() == True: self.__showJson() return - print('%-20s%-8s%-8s%-12s%-12s%-8s%-8s%-8s%-8s' % - (("device-stat:"), "r_iops", "w_iops", "r_bps", - "w_bps", "wait", "r_wait", "w_wait", "util%")) - for devname, stat in deviceStatDicts.items(): - if self.deviceStatDicts[devname]['util%'] < 0: + print('%-20s%-8s%-8s%-12s%-12s%-8s%-8s%-8s%-8s' %\ + (("device-stat:"),"r_iops","w_iops","r_bps",\ + "w_bps","wait","r_wait","w_wait","util%")) + stSecs = str(secs)+'s' if secs > 1 else 's' + for devname,stat in deviceStatDicts.items(): + if stat['util%'] < 0: continue - print('%-20s%-8s%-8s%-12s%-12s%-8s%-8s%-8s%-8s' % - (devname, str(stat['r_iops']), str(stat['w_iops']), humConvert(stat['r_bps'], True), - humConvert(stat['w_bps'], True), str(stat['wait']), str( - stat['r_wait']), str(stat['w_wait']), - str(stat['util%']))) + stWbps = humConvert(stat['w_bps'], True).replace('s', stSecs) if stat['w_bps'] else 0 + stRbps = humConvert(stat['r_bps'], True).replace('s', stSecs) if stat['r_bps'] else 0 + print('%-20s%-8s%-8s%-12s%-12s%-8s%-8s%-8s%-8s' %\ + (devname, str(stat['r_iops']), str(stat['w_iops']), stRbps, stWbps, + str(stat['wait']), str(stat['r_wait']), str(stat['w_wait']), str(stat['util%']))) print("") def clear(self): self.f.close() - + if self.enableJsonShow(): + self.fJson.close() + def notCareDevice(self, devname): - if self.deviceStatDicts[devname]['util%'] < 0: + if not self.nodiskStat and self.deviceStatDicts[devname]['util%'] < 0: return True return False - + def disableShow(self): deviceStatDicts = self.deviceStatDicts - for devname, stat in deviceStatDicts.items(): + for devname,stat in deviceStatDicts.items(): if self.deviceStatDicts[devname]['util%'] >= 0: return False return True - + def getDiskBW(self): bw = 0 deviceStatDicts = self.deviceStatDicts - for devname, stat in deviceStatDicts.items(): + for devname,stat in deviceStatDicts.items(): if self.deviceStatDicts[devname]['util%'] >= 0: bw += (int(stat['r_bps'])+int(stat['w_bps'])) return bw - + def enableJsonShow(self): - return self.json + return True if self.json else False + + def writeDataToJson(self, data): + self.fJson.write(data+'\n') diff --git a/source/tools/detect/io/iofsstat/fsstatClass.py b/source/tools/detect/io/iofsstat/fsstatClass.py old mode 100644 new mode 100755 index 9a25e0a9..2940c6a5 --- a/source/tools/detect/io/iofsstat/fsstatClass.py +++ b/source/tools/detect/io/iofsstat/fsstatClass.py @@ -12,13 +12,12 @@ from collections import OrderedDict from diskstatClass import diskstatClass from diskstatClass import getDevt from diskstatClass import humConvert +from subprocess import PIPE, Popen def execCmd(cmd): - r = os.popen(cmd+" 2>/dev/null") - text = r.read() - r.close() - return text + p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) + return p.stdout.read().decode('utf-8') def getTgid(pid): @@ -126,38 +125,35 @@ def getFullName(fileInfoDict): def echoFile(filename, txt): - execCmd("echo \""+txt+"\" > "+filename) + execCmd("echo \'"+txt+"\' > "+filename) def echoFileAppend(filename, txt): - execCmd("echo \""+txt+"\" >> "+filename) + execCmd("echo \'"+txt+"\' >> "+filename) def supportKprobe(name): - cmd = "cat /sys/kernel/debug/tracing/available_filter_functions |grep " + name - ss = execCmd(cmd).strip() - for res in ss.split('\n'): - if ':' in res: - res = res.split(":", 1)[1] - if ' [' in res: # for ko symbol - res = res.split(" [", 1)[0] - if res == name: - return True + file = '/sys/kernel/debug/tracing/available_filter_functions' + with open(file) as f: + ss = f.read() + if ss.find(name) > 0: + return True return False class fsstatClass(diskstatClass): - def __init__(self, devname, pid, utilThresh, cycle, bwThresh, top, json): - super(fsstatClass, self).__init__(devname, utilThresh, cycle, json) + def __init__(self, devname, pid, utilThresh, bwThresh, top, json, nodiskStat, miscStat): + super(fsstatClass, self).__init__(devname, utilThresh, json, nodiskStat) self.expression = [] self.pid = pid self.devname = devname + self.miscStat = miscStat self.top = int(top) if top is not None else 99999999 self.bwThresh = int(bwThresh) if bwThresh is not None else 0 self.devt = getDevt(self.devname) if devname is not None else -1 tracingBaseDir = "/sys/kernel/debug/tracing" self.kprobeEvent = tracingBaseDir+"/kprobe_events" - self.tracingDir = tracingBaseDir+'/instances/iofsstat' + self.tracingDir = tracingBaseDir+'/instances/iofsstat4fs' self.kprobeDir = self.tracingDir+"/events/kprobes" self.kprobe = [] self.inputExp = [] @@ -168,7 +164,7 @@ class fsstatClass(diskstatClass): int(version[0]) == 3 and int(version[1]) > 10) else '0x8' offlen = '0x10' if int(version[0]) <= 3: - offlen = '0x8' if 'ali' in vinfo else '0x18' + offlen = '0x8' if int(version[1]) < 13 else '0x18' arch = execCmd('lscpu | grep Architecture').split( ":", 1)[1].strip() if arch.startswith("arm"): @@ -188,8 +184,8 @@ class fsstatClass(diskstatClass): 'bfname=+0x0(+0x28(+0x18(%s))):string '\ 'd1fname=+0x0(+0x28(+0x18(+0x18(%s)))):string '\ 'd2fname=+0x0(+0x28(+0x18(+0x18(+0x18(%s))))):string '\ - 'd3fname=+0x0(+0x28(+0x18(+0x18(+0x18(+0x18(%s)))))):string ' % \ - (argv0, argv0, argv1, argv0, argv0, argv0, argv0, argv0) + 'd3fname=+0x0(+0x28(+0x18(+0x18(+0x18(+0x18(%s)))))):string '\ + 'comm=$comm' % (argv0, argv0, argv1, argv0, argv0, argv0, argv0, argv0) devList = [] if self.devname is not None: @@ -204,40 +200,22 @@ class fsstatClass(diskstatClass): for entry in self.fsmountInfo: fstype = entry.split()[2] - kprobe = fstype+"_file_write_iter" - if kprobe in self.kprobe: - continue - if supportKprobe(kprobe): - pass - elif supportKprobe(fstype+"_file_write"): - kprobe = fstype+"_file_write" - elif supportKprobe(fstype+"_file_aio_write"): - kprobe = fstype+"_file_aio_write" - elif supportKprobe("generic_file_aio_write"): - kprobe = "generic_file_aio_write" - else: - print("not available write kprobe") - sys.exit(0) - writeKprobe = 'p '+kprobe+' '+kprobeArgs - self.kprobe.append(kprobe) - self.inputExp.append(writeKprobe) - - kprobe = fstype+"_file_read_iter" - if supportKprobe(kprobe): - pass - elif supportKprobe(fstype+"_file_read"): - kprobe = fstype+"_file_read" - elif supportKprobe(fstype+"_file_aio_read"): - kprobe = fstype+"_file_aio_read" - elif supportKprobe("generic_file_aio_read"): - kprobe = "generic_file_aio_read" - else: - print("not available read kprobe") - sys.exit(0) - readKprobe = 'p '+kprobe+' '+kprobeArgs - self.kprobe.append(kprobe) - self.inputExp.append(readKprobe) - + for op in ['write', 'read']: + kPoints = [fstype+"_file_"+op+"_iter", fstype+"_file_"+op, + fstype+"_file_aio_"+op, "generic_file_aio_"+op] + if list(set(self.kprobe) & set(kPoints)): + continue + kprobe = None + for k in kPoints: + if supportKprobe(k): + kprobe = k + break + if not kprobe: + print("not available %s kprobe" % op) + sys.exit(0) + pointKprobe = 'p '+kprobe+' '+kprobeArgs + self.kprobe.append(kprobe) + self.inputExp.append(pointKprobe) self.expression = self.inputExp self.outlogFormatBase = 10 @@ -249,10 +227,10 @@ class fsstatClass(diskstatClass): for exp in self.expression: probe = 'p_'+exp.split()[1]+'_0' enableKprobe = self.kprobeDir+"/"+probe+"/enable" + filterKprobe = self.kprobeDir+"/"+probe+"/filter" if os.path.exists(enableKprobe): echoFile(enableKprobe, "0") if devt > 0: - filterKprobe = self.kprobeDir+"/"+probe+"/filter" echoFile(filterKprobe, "0") echoFileAppend(self.kprobeEvent, '-:%s' % probe) @@ -278,6 +256,8 @@ class fsstatClass(diskstatClass): for exp in self.expression: probe = 'p_'+exp.split()[1]+'_0' enableKprobe = self.kprobeDir+"/"+probe+"/enable" + if not os.path.exists(enableKprobe): + continue echoFile(enableKprobe, "0") if self.devt > 0: filterKprobe = self.kprobeDir+"/"+probe+"/filter" @@ -287,84 +267,67 @@ class fsstatClass(diskstatClass): def showJson(self, stat): secs = self.cycle - top = 0 - statJsonStr = '{\ - "time":"",\ - "fsstats":[]}' + statJsonStr = '{"time":"","fsstats":[]}' fstatDicts = json.loads(statJsonStr, object_pairs_hook=OrderedDict) fstatDicts['time'] = time.strftime( '%Y/%m/%d %H:%M:%S', time.localtime()) + stSecs = str(secs)+'s' if secs > 1 else 's' for key, item in stat.items(): if (item["cnt_wr"] + item["cnt_rd"]) == 0: continue - if top >= self.top: - break - top += 1 - item["cnt_wr"] /= secs - item["bw_wr"] = humConvert(item["bw_wr"]/secs, True) - item["cnt_rd"] /= secs - item["bw_rd"] = humConvert(item["bw_rd"]/secs, True) + item["bw_wr"] = \ + humConvert(item["bw_wr"], True).replace('s', stSecs) if item["bw_wr"] else 0 + item["bw_rd"] = \ + humConvert(item["bw_rd"], True).replace('s', stSecs) if item["bw_rd"] else 0 fsstatJsonStr = '{\ - "inode":0,\ - "comm":"",\ - "tgid":0,\ - "pid":0,\ - "cnt_rd":0,\ - "bw_rd":0,\ - "cnt_wr":0,\ - "bw_wr":0,\ - "device":0,\ - "file":0}' + "inode":0,"comm":"","tgid":0,"pid":0,"cnt_rd":0,\ + "bw_rd":0,"cnt_wr":0,"bw_wr":0,"device":0,"file":0}' fsstatDict = json.loads( fsstatJsonStr, object_pairs_hook=OrderedDict) - fsstatDict["inode"] = key for key, val in item.items(): fsstatDict[key] = val fstatDicts["fsstats"].append(fsstatDict) if len(fstatDicts["fsstats"]) > 0: - print(json.dumps(fstatDicts)) + self.writeDataToJson(json.dumps(fstatDicts)) def show(self): - top = 0 bwTotal = 0 stat = {} + mStat = {} secs = self.cycle with open(self.tracingDir+"/trace") as f: - traceText = list(filter( - lambda x: any(e in x for e in self.kprobe), - f.readlines())) + traceText = \ + list(filter(lambda x: any(e in x for e in self.kprobe), f.readlines())) # pool-1-thread-2-5029 [002] .... 5293018.252338: p_ext4_file_write_iter_0:\ # (ext4_file_write_iter+0x0/0x6d0 [ext4]) dev=265289729 inode_num=530392 len=38 # ... for entry in traceText: - matchObj = re.match(r'(.*) \[([^\[\]]*)\] (.*) dev=(.*) ' + - 'inode_num=(.*) len=(.*) mntfname=(.*) ' + - 'bfname=(.*) d1fname=(.*) d2fname=(.*) d3fname=(.*)\n', entry) - # print(entry) - if matchObj is not None: - commInfo = matchObj.group(1).rsplit('-', 1) - else: - continue - pid = commInfo[1].strip() - if self.pid is not None and pid != self.pid: + matchObj = re.match( + r'(.*) \[([^\[\]]*)\] (.*) dev=(.*) inode_num=(.*) len=(.*)'+ + ' mntfname=(.*) bfname=(.*) d1fname=(.*) d2fname=(.*) d3fname=(.*) comm=(.*)\n', + entry) + #print(entry) + if matchObj is None: continue + pid = (matchObj.group(1).rsplit('-', 1))[1].strip() dev = int(matchObj.group(4), self.outlogFormatBase) - if self.devt > 0 and self.devt != dev: + if (self.pid is not None and pid != self.pid) or \ + (self.devt > 0 and self.devt != dev): continue - device = super(fsstatClass, self).getDevNameByDevt(dev) - # if super(fsstatClass, self).notCareDevice(device) == True: - # continue + device = self.getDevNameByDevt(dev) + if self.miscStat is not None: + disk = self.getMasterDev(device) + if not mStat.has_key(disk): + mStat.setdefault(disk, {}) + stat = mStat[disk] ino = int(matchObj.group(5), self.outlogFormatBase) - if bool(stat.has_key(ino)) != True: - comm = fixComm(commInfo[0].lstrip(), pid) - if '..' in comm: - continue - fsmountinfo = [] - for f in self.fsmountInfo: - if ('/dev/'+device) in f: - fsmountinfo.append(f) - + comm = fixComm(matchObj.group(12).strip("\""), pid) + if '..' in comm: + continue + inoTask = str(ino)+':'+str(comm)+':'+device + if not stat.has_key(inoTask): + fsmountinfo = [f for f in self.fsmountInfo if ('/dev/'+device) in f] fileInfoDict = { 'device': device, 'mntfname': matchObj.group(7).strip("\""), @@ -372,56 +335,70 @@ class fsstatClass(diskstatClass): 'd1fname': matchObj.group(9).strip("\""), 'd2fname': matchObj.group(10).strip("\""), 'd3fname': matchObj.group(11).strip("\""), - 'fsmountinfo': fsmountinfo, - 'ino': ino, 'pid': pid} - stat.setdefault(ino, - {"comm": comm, "tgid": getTgid(pid), "pid": pid, - "cnt_wr": 0, "bw_wr": 0, "cnt_rd": 0, "bw_rd": 0, - "device": device, - "file": getFullName(fileInfoDict)}) + 'fsmountinfo': fsmountinfo, 'ino': ino, 'pid': pid} + stat.setdefault( + inoTask, + {"inode":str(ino), "comm": comm, "tgid": getTgid(pid), "pid": pid, + "cnt_wr": 0, "bw_wr": 0, "cnt_rd": 0, "bw_rd": 0, "device": device, + "file": getFullName(fileInfoDict)}) size = int(matchObj.group(6), self.outlogFormatBase) if 'write' in entry: - stat[ino]["cnt_wr"] += 1 - stat[ino]["bw_wr"] += int(size) + stat[inoTask]["cnt_wr"] += 1 + stat[inoTask]["bw_wr"] += int(size) if 'read' in entry: - stat[ino]["cnt_rd"] += 1 - stat[ino]["bw_rd"] += int(size) + stat[inoTask]["cnt_rd"] += 1 + stat[inoTask]["bw_rd"] += int(size) + if pid != stat[inoTask]["pid"]: + stat[inoTask]["pid"] = pid + stat[inoTask]["tgid"] = getTgid(pid) bwTotal += int(size) - if (bwTotal/secs) < self.bwThresh or \ - ((self.bwThresh > 0 and - (bwTotal/secs) < super(fsstatClass, self).getDiskBW())): + if self.miscStat is not None: + for d,val in self.miscStat: + if d not in mStat.keys(): + mStat.setdefault(d, {}) + mStat[d].update(dict(val)) + tmpStat = [] + for d,val in mStat.items(): + idxSort = 'bw_wr' + if self.getDiskStatInd(d, 'w_iops') < self.getDiskStatInd(d, 'r_iops'): + idxSort = 'bw_rd' + s = sorted(val.items(), key=lambda e: (e[1][idxSort]), reverse=True)[:self.top] + tmpStat.append((d, s)) + del self.miscStat[:] + self.miscStat.extend(tmpStat) return + else: + if (self.bwThresh and (bwTotal/secs) < self.bwThresh): + return + + stat = sorted(stat.items(), key=lambda e: ( + e[1]["bw_wr"]+e[1]["bw_rd"]), reverse=True)[:self.top] - if super(fsstatClass, self).enableJsonShow() == False: + if self.enableJsonShow() == False: print(time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())) - if super(fsstatClass, self).disableShow() == False: + if self.disableShow() == False: super(fsstatClass, self).show() - if stat: - stat = OrderedDict(sorted(stat.items(), - key=lambda e: (e[1]["bw_wr"]+e[1]["bw_rd"]), reverse=True)) - if super(fsstatClass, self).enableJsonShow() == True: + if self.enableJsonShow() == True: self.showJson(stat) return print("%-20s%-8s%-8s%-8s%-12s%-8s%-12s%-12s%-12s%s" % ("comm", "tgid", "pid", "cnt_rd", "bw_rd", "cnt_wr", "bw_wr", "inode", "device", "filepath")) - for key, item in stat.items(): + stSecs = str(secs)+'s' if secs > 1 else 's' + for key, item in stat: if (item["cnt_wr"] + item["cnt_rd"]) == 0: continue - if top >= self.top: - break - top += 1 - item["cnt_wr"] /= secs - item["bw_wr"] = humConvert(item["bw_wr"]/secs, True) - item["cnt_rd"] /= secs - item["bw_rd"] = humConvert(item["bw_rd"]/secs, True) + item["bw_wr"] = \ + humConvert(item["bw_wr"], True).replace('s', stSecs) if item["bw_wr"] else 0 + item["bw_rd"] = \ + humConvert(item["bw_rd"], True).replace('s', stSecs) if item["bw_rd"] else 0 print("%-20s%-8s%-8s%-8d%-12s%-8d%-12s%-12s%-12s%s" - % (item["comm"], item["tgid"], item["pid"], - item["cnt_rd"], item["bw_rd"], item["cnt_wr"], - item["bw_wr"], key, item["device"], item["file"])) + % (item["comm"], item["tgid"], item["pid"], item["cnt_rd"], + item["bw_rd"], item["cnt_wr"], item["bw_wr"], item["inode"], + item["device"], item["file"])) print("") def entry(self, interval): diff --git a/source/tools/detect/io/iofsstat/iofsstat.py b/source/tools/detect/io/iofsstat/iofsstat.py old mode 100644 new mode 100755 index 262329f0..dace9441 --- a/source/tools/detect/io/iofsstat/iofsstat.py +++ b/source/tools/detect/io/iofsstat/iofsstat.py @@ -9,6 +9,8 @@ import argparse from collections import OrderedDict from iostatClass import iostatClass from fsstatClass import fsstatClass +from promiscClass import promiscClass +import time global_stop = False @@ -24,34 +26,33 @@ def main(): sys.exit(0) examples = """e.g. ./iofsstat.py -d vda -c 1 - Report IO statistic for vda per 1secs + Report IO statistic for vda per 1secs ./iofsstat.py -d vda1 --fs -c 1 - Report fs IO statistic for vda1 per 1secs - """ + Report fs IO statistic for vda1 per 1secs + """ parser = argparse.ArgumentParser( description="Report IO statistic for partitions.", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) - parser.add_argument('-T', '--Timeout', - help='Specify the timeout for program exit(secs).') - parser.add_argument( - '-t', '--top', help='Report the TopN with the largest IO resources.') - parser.add_argument('-u', '--util_thresh', - help='Specify the util-thresh to report.') - parser.add_argument('-b', '--bw_thresh', - help='Specify the BW-thresh to report.') - parser.add_argument('-i', '--iops_thresh', - help='Specify the IOPS-thresh to report.') - parser.add_argument('-c', '--cycle', help='Specify refresh cycle(secs).') - parser.add_argument('-d', '--device', help='Specify the disk name.') - parser.add_argument('-p', '--pid', help='Specify the process id.') - parser.add_argument('-j', '--json', action='store_true', - help='Specify the json-format output.') - parser.add_argument('-f', '--fs', action='store_true', - help='Report filesystem statistic for partitions.') + parser.add_argument('-T','--Timeout', help='Specify the timeout for program exit(secs).') + parser.add_argument('-t','--top', help='Report the TopN with the largest IO resources.') + parser.add_argument('-u','--util_thresh', help='Specify the io util-thresh to report.') + parser.add_argument('-b','--bw_thresh', help='Specify the BW-thresh to report.') + parser.add_argument('-i','--iops_thresh', help='Specify the IOPS-thresh to report.') + parser.add_argument('-c','--cycle', help='Specify refresh cycle(secs).') + parser.add_argument('-d','--device', help='Specify the disk name.') + parser.add_argument('-p','--pid', help='Specify the process id.') + parser.add_argument('-j','--json', help='Specify the json-format output.') + parser.add_argument('-f','--fs', action='store_true', + help='Report filesystem statistic for partitions.') + parser.add_argument('-n','--nodiskStat', action='store_true', + help='Not report disk stat.') + parser.add_argument('-m','--misc', action='store_true', + help='Promiscuous mode.') + args = parser.parse_args() - secs = int(args.cycle) if args.cycle is not None else 0 + secs = float(args.cycle) if args.cycle is not None else 0 devname = args.device pid = int(args.pid) if args.pid else None signal.signal(signal.SIGINT, signal_exit_handler) @@ -59,18 +60,23 @@ def main(): signal.signal(signal.SIGTERM, signal_exit_handler) if args.Timeout is not None: timeoutSec = args.Timeout if args.Timeout > 0 else 10 + secs = secs if secs > 0 else 1 signal.signal(signal.SIGALRM, signal_exit_handler) signal.alarm(int(timeoutSec)) - secs = 1 loop = True if secs > 0 else False - if args.fs: - c = fsstatClass(devname, pid, args.util_thresh, secs, args.bw_thresh, - args.top, args.json) + interval = secs if loop == True else 1 + if args.misc: + c = promiscClass(devname, args.util_thresh, args.iops_thresh, + args.bw_thresh, args.top, args.json, args.nodiskStat) else: - c = iostatClass(devname, pid, args.util_thresh, secs, args.iops_thresh, - args.bw_thresh, args.top, args.json) + if args.fs: + c = fsstatClass(devname, pid, args.util_thresh, args.bw_thresh, + args.top, args.json, args.nodiskStat, None) + else: + c = iostatClass(devname, pid, args.util_thresh, args.iops_thresh, + args.bw_thresh, args.top, args.json, args.nodiskStat, None) + c.config() - interval = secs if loop == True else 1 while global_stop != True: c.entry(interval) if loop == False: diff --git a/source/tools/detect/io/iofsstat/iostatClass.py b/source/tools/detect/io/iofsstat/iostatClass.py old mode 100644 new mode 100755 index 9e8c4606..c5c8ae33 --- a/source/tools/detect/io/iofsstat/iostatClass.py +++ b/source/tools/detect/io/iofsstat/iostatClass.py @@ -12,13 +12,12 @@ from collections import OrderedDict from diskstatClass import diskstatClass from diskstatClass import getDevt from diskstatClass import humConvert +from subprocess import PIPE, Popen def execCmd(cmd): - r = os.popen(cmd+" 2>/dev/null") - text = r.read() - r.close() - return text + p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) + return p.stdout.read().decode('utf-8') def echoFile(filename, txt): @@ -26,15 +25,17 @@ def echoFile(filename, txt): class iostatClass(diskstatClass): - def __init__(self, devname, pid, utilThresh, cycle, iopsThresh, bwThresh, top, json): - super(iostatClass, self).__init__(devname, utilThresh, cycle, json) + def __init__(self, devname, pid, utilThresh, iopsThresh, bwThresh, top, json, nodiskStat, miscStat): + super(iostatClass, self).__init__( + devname, utilThresh, json, nodiskStat) self.pid = pid self.devname = devname + self.miscStat = miscStat self.top = int(top) if top is not None else 99999999 self.iopsThresh = int(iopsThresh) if iopsThresh is not None else 0 self.bwThresh = int(bwThresh) if bwThresh is not None else 0 self.devt = getDevt(self.devname) if devname is not None else -1 - self.tracingDir = "/sys/kernel/debug/tracing/instances/iofsstat" + self.tracingDir = "/sys/kernel/debug/tracing/instances/iofsstat4io" self.blkTraceDir = self.tracingDir+"/events/block" def config(self): @@ -61,46 +62,33 @@ class iostatClass(diskstatClass): super(iostatClass, self).clear() def showJson(self, stat): - top = 0 secs = self.cycle - statJsonStr = '{\ - "time":"",\ - "iostats":[]}' + statJsonStr = '{"time":"","iostats":[]}' iostatDicts = json.loads(statJsonStr, object_pairs_hook=OrderedDict) iostatDicts['time'] = time.strftime( '%Y/%m/%d %H:%M:%S', time.localtime()) + stSecs = str(secs)+'s' if secs > 1 else 's' for key, item in stat.items(): if (item["iops_rd"] + item["iops_wr"]) == 0: continue - if top >= self.top: - break - top += 1 - item["iops_rd"] /= secs - item["iops_wr"] /= secs - item["bps_rd"] = humConvert(item["bps_rd"]/secs, True) - item["bps_wr"] = humConvert(item["bps_wr"]/secs, True) + item["bps_rd"] = \ + humConvert(item["bps_rd"], True).replace('s', stSecs) if item["bps_rd"] else 0 + item["bps_wr"] = \ + humConvert(item["bps_wr"], True).replace('s', stSecs) if item["bps_wr"] else 0 iostatJsonStr = '{\ - "comm":"",\ - "pid":0,\ - "bps_rd":0,\ - "iops_rd":0,\ - "iops_wr":0,\ - "bps_wr":0,\ - "device":0}' - iostatDict = json.loads( - iostatJsonStr, object_pairs_hook=OrderedDict) - iostatDict["comm"] = key - for key in ['pid', 'bps_rd', 'iops_rd', 'iops_wr', 'bps_wr', 'device']: + "comm":"","pid":0,"bps_rd":0,"iops_rd":0,"iops_wr":0,"bps_wr":0,"device":0}' + iostatDict = json.loads(iostatJsonStr, object_pairs_hook=OrderedDict) + for key in ['comm', 'pid', 'bps_rd', 'iops_rd', 'iops_wr', 'bps_wr', 'device']: iostatDict[key] = item[key] iostatDicts["iostats"].append(iostatDict) if len(iostatDicts["iostats"]) > 0: - print(json.dumps(iostatDicts)) + self.writeDataToJson(json.dumps(iostatDicts)) def show(self): - top = 0 iopsTotal = 0 bwTotal = 0 stat = {} + mStat = {} secs = self.cycle with open(self.tracingDir+"/trace") as f: traceText = list( @@ -118,62 +106,76 @@ class iostatClass(diskstatClass): dev = ((int(devinfo[0]) << 20) + int(devinfo[1])) if self.devt > 0 and self.devt != dev: continue - device = super(iostatClass, self).getDevNameByDevt(dev) - if super(iostatClass, self).notCareDevice(device) == True: + device = self.getDevNameByDevt(dev) + if self.notCareDevice(device) == True: continue + if self.miscStat is not None: + if not mStat.has_key(device): + mStat.setdefault(device, {}) + stat = mStat[device] iotype = oneIO[-5-comm.count(' ')] sectors = oneIO[-2-comm.count(' ')] - if bool(stat.has_key(comm)) != True: - stat.setdefault(comm, - {"pid": pid, "iops_rd": 0, - "iops_wr": 0, "bps_rd": 0, - "bps_wr": 0, "flushIO": 0, - "device": device}) + task = str(pid)+':'+device + if bool(stat.has_key(task)) != True: + stat.setdefault(task, + {"comm":comm, "pid": pid, "iops_rd": 0, + "iops_wr": 0, "bps_rd": 0, "bps_wr": 0, + "flushIO": 0, "device": device}) if 'R' in iotype: - stat[comm]["iops_rd"] += 1 - stat[comm]["bps_rd"] += (int(sectors) * 512) + stat[task]["iops_rd"] += 1 + stat[task]["bps_rd"] += (int(sectors) * 512) bwTotal += (int(sectors) * 512) iopsTotal += 1 if 'W' in iotype: - stat[comm]["iops_wr"] += 1 - stat[comm]["bps_wr"] += (int(sectors) * 512) + stat[task]["iops_wr"] += 1 + stat[task]["bps_wr"] += (int(sectors) * 512) bwTotal += (int(sectors) * 512) iopsTotal += 1 if 'F' in iotype: - stat[comm]["flushIO"] += 1 + stat[task]["flushIO"] += 1 - if super(iostatClass, self).disableShow() == True or \ - ((iopsTotal/secs) < self.iopsThresh and - (bwTotal/secs) < self.bwThresh): - return + if self.iopsThresh or self.bwThresh: + if (self.bwThresh and bwTotal >= self.bwThresh) or \ + (self.iopsThresh and iopsTotal >= self.iopsThresh): + pass + else: + return - if super(iostatClass, self).enableJsonShow() == False: + if self.enableJsonShow() == False: print(time.strftime('%Y/%m/%d %H:%M:%S', time.localtime())) super(iostatClass, self).show() - if stat: - stat = OrderedDict(sorted(stat.items(), - key=lambda e: ( - e[1]["iops_rd"] + e[1]["iops_wr"]), - reverse=True)) - if super(iostatClass, self).enableJsonShow() == True: + if self.miscStat is not None: + tmpStat = [] + for d,val in mStat.items(): + s = sorted(val.items(), + key=lambda e: (e[1]["bps_wr"]+e[1]["bps_rd"]), + reverse=True)[:self.top] + tmpStat.append((d, s)) + del self.miscStat[:] + self.miscStat.extend(tmpStat) + return + + stat = sorted(stat.items(), + key=lambda e: (e[1]["iops_rd"] + e[1]["iops_wr"]), + reverse=True)[:self.top] + + if self.enableJsonShow() == True: self.showJson(stat) return print('%-20s%-8s%-12s%-16s%-12s%-12s%s' % ("comm", "pid", "iops_rd", "bps_rd", "iops_wr", "bps_wr", "device")) - for key, item in stat.items(): + stSecs = str(secs)+'s' if secs > 1 else 's' + for key, item in stat: if (item["iops_rd"] + item["iops_wr"]) == 0: continue - if top >= self.top: - break - top += 1 - item["iops_rd"] /= secs - item["iops_wr"] /= secs - item["bps_rd"] = humConvert(item["bps_rd"]/secs, True) - item["bps_wr"] = humConvert(item["bps_wr"]/secs, True) + item["bps_rd"] = \ + humConvert(item["bps_rd"], True).replace('s', stSecs) if item["bps_rd"] else 0 + item["bps_wr"] = \ + humConvert(item["bps_wr"], True).replace('s', stSecs) if item["bps_wr"] else 0 print('%-20s%-8s%-12s%-16s%-12s%-12s%s' % - (key, str(item["pid"]), str(item["iops_rd"]), + (item["comm"], str(item["pid"]), str(item["iops_rd"]), item["bps_rd"], str(item["iops_wr"]), item["bps_wr"], item["device"])) print("") diff --git a/source/tools/detect/io/iofsstat/promiscClass.py b/source/tools/detect/io/iofsstat/promiscClass.py new file mode 100755 index 00000000..276584d5 --- /dev/null +++ b/source/tools/detect/io/iofsstat/promiscClass.py @@ -0,0 +1,193 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +import sys +import signal +import string +import time +import re +import json +from collections import OrderedDict +from diskstatClass import humConvert +from iostatClass import iostatClass +from fsstatClass import fsstatClass + + +class promiscClass(): + def __init__(self, devname, utilThresh, iopsThresh, bwThresh, top, json, nodiskStat): + self._iostat = [] + self._fsstat = [] + self.fs = fsstatClass(devname, None, utilThresh, bwThresh, + top, json, nodiskStat, self._fsstat) + self.io = iostatClass(devname, None, utilThresh, iopsThresh, + bwThresh, top, json, nodiskStat, self._iostat) + + + def _selectKworker(self, iostat, fsItem, kworker): + select = None + largeFound = False + diff = sys.maxsize + for k in kworker: + fsRestBw = fsItem["bw_wr"] + if 'restBW' in fsItem.keys(): + fsRestBw = fsItem["restBW"] + if fsRestBw > (iostat[k]["bps_wr"] * 15) or \ + (fsRestBw * 50) < iostat[k]["bps_wr"]: + continue + d = abs(fsItem["bw_wr"] - iostat[k]["bps_wr"]) + diff = min(d, diff) + if iostat[k]["bps_wr"] > fsItem["bw_wr"]: + if not largeFound or diff == d: + select = k + largeFound = True + continue + if not largeFound and diff == d: + select = k + return select + + + def _addBioToKworker(self, iostat, kworker, fsItem): + repeated = False + k = self._selectKworker(iostat, fsItem, kworker) + if not k: + return False, 0 + if 'bufferio' not in iostat[k].keys(): + iostat[k].setdefault('bufferio', []) + task = fsItem["comm"]+':'+str(fsItem["tgid"])+':'+str(fsItem["pid"]) + bio = {'task': task, 'Wrbw': fsItem["bw_wr"], 'file': fsItem["file"], + 'device': fsItem["device"]} + for d in iostat[k]["bufferio"]: + if task == d['task'] and d['file'] == bio['file'] and d['device'] == bio['device']: + d['Wrbw'] = max(d['Wrbw'], bio["Wrbw"]) + repeated = True + break + if not repeated: + iostat[k]["bufferio"].append(bio) + return True, iostat[k]["bps_wr"] + + + def _checkDeleteItem(self, valid, costBW, item): + if 'restBW' not in item.keys(): + item.setdefault('restBW', item["bw_wr"]) + item.setdefault('added', 0) + item["added"] = item["added"] + 1 if valid else item["added"] - 1 + item["restBW"] = item["restBW"] - costBW if valid else item["restBW"] + if item["restBW"] <= 0 or (item["restBW"] < item["bw_wr"] and item["added"] <= -2): + return True + return False + + + def _miscIostatFromFsstat(self): + fsstats = self._fsstat + iostats = dict(self._iostat) + for disk, fsItems in fsstats: + if disk not in iostats.keys(): + continue + rmList = [] + iostat = dict(iostats[disk]) + kworker = [key for key,val in iostat.items() if 'kworker' in val['comm']] + for key, item in fsItems: + taskI = item["pid"]+':'+disk + if taskI in iostat.keys(): + if 'file' not in iostat[taskI].keys(): + iostat[taskI].setdefault('file', []) + iostat[taskI]["file"].append(item["file"]) + rmList.append((key, item)) + continue + if kworker: + if item["bw_wr"] < item["bw_rd"]: + rmList.append((key, item)) + continue + added,cost = self._addBioToKworker(iostat, kworker, item) + deleted = self._checkDeleteItem(added, cost, item) + if deleted: + rmList.append((key, item)) + for key, item in rmList: + fsItems.remove((key, item)) + iostats[disk] = iostat + return iostats + + + def _miscShowJson(self, iostats): + secs = self.io.cycle + statJsonStr = '{"time":"","mstats":[]}' + mstatDicts = json.loads(statJsonStr, object_pairs_hook=OrderedDict) + mstatDicts['time'] = time.strftime('%Y/%m/%d %H:%M:%S', time.localtime()) + stSecs = str(secs)+'s' if secs > 1 else 's' + for disk, iostat in iostats.items(): + for key, item in dict(iostat).items(): + if (item["iops_rd"]+item["iops_wr"]) == 0 or (item["bps_rd"]+item["bps_wr"]) == 0: + continue + item["bps_rd"] = humConvert( + item["bps_rd"], True).replace('s', str(secs)+'s') if item["bps_rd"] else '0' + item["bps_wr"] = humConvert( + item["bps_wr"], True).replace('s', str(secs)+'s') if item["bps_wr"] else '0' + if 'file' not in item.keys(): + item.setdefault('file', '-') + if 'kworker' in item["comm"] and 'bufferio' in item.keys(): + for i in item["bufferio"]: + i["Wrbw"] = humConvert(i["Wrbw"], True).replace('s', str(secs)+'s') + mstatDicts["mstats"].append(item) + if len(mstatDicts["mstats"]) > 0: + self.io.writeDataToJson(json.dumps(mstatDicts)) + + + def miscShow(self): + secs = self.io.cycle + if not self._fsstat and not self._iostat: + return + + iostats = self._miscIostatFromFsstat() + if self.io.enableJsonShow() == True: + self._miscShowJson(iostats) + return + + print('%-20s%-8s%-12s%-16s%-12s%-12s%-8s%s' % + ("comm", "pid", "iops_rd", "bps_rd", "iops_wr", "bps_wr", "device", "file")) + for disk, iostat in iostats.items(): + for key, item in dict(iostat).items(): + if (item["iops_rd"]+item["iops_wr"]) == 0 or (item["bps_rd"]+item["bps_wr"]) == 0: + continue + item["bps_rd"] = humConvert( + item["bps_rd"], True).replace('s', str(secs)+'s') if item["bps_rd"] else '0' + item["bps_wr"] = humConvert( + item["bps_wr"], True).replace('s', str(secs)+'s') if item["bps_wr"] else '0' + file = str(item["file"]) if 'file' in item.keys() else '-' + print('%-20s%-8s%-12s%-16s%-12s%-12s%-8s%s' % + (item["comm"], str(item["pid"]), str(item["iops_rd"]), item["bps_rd"], + str(item["iops_wr"]), item["bps_wr"], item["device"], file)) + if 'kworker' in item["comm"] and 'bufferio' in item.keys(): + for i in item["bufferio"]: + i["Wrbw"] = humConvert(i["Wrbw"], True).replace('s', str(secs)+'s') + print(' |----%-32s WrBw:%-12s Device:%-8s File:%s' % + (i['task'], i["Wrbw"], i["device"], i["file"])) + print("") + + + def config(self): + self.fs.config() + self.io.config() + + def start(self): + self.clear() + self.fs.start() + self.io.start() + + def stop(self): + self.fs.stop() + self.io.stop() + + def clear(self): + del self._iostat[:] + + def show(self): + self.fs.show() + self.io.show() + self.miscShow() + + def entry(self, interval): + self.start() + time.sleep(float(interval)) + self.stop() + self.show() -- Gitee From 591bbcee3ef465b9ea2c497a2b315c54c2b0b75b Mon Sep 17 00:00:00 2001 From: "guangshui.li" Date: Fri, 2 Sep 2022 14:53:14 +0800 Subject: [PATCH 3/4] iosdiag: Fix bugs 'run iosdiag error' in different python version Signed-off-by: guangshui.li --- source/tools/combine/iosdiag/entry/iosdiag.sh | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/source/tools/combine/iosdiag/entry/iosdiag.sh b/source/tools/combine/iosdiag/entry/iosdiag.sh index d16dde88..1aa5d28b 100755 --- a/source/tools/combine/iosdiag/entry/iosdiag.sh +++ b/source/tools/combine/iosdiag/entry/iosdiag.sh @@ -43,7 +43,21 @@ upload_data() { datafile_analysis() { if [ -e "$logfile" ] then - python $data_analysis --$1 -s -f $logfile $threshold_arg + run_python = "python" + if [ -e "/usr/bin/python" ]; then + run_python = "/usr/bin/python" + elif [ -e "/usr/bin/python2" ]; then + run_python = "/usr/bin/python2" + elif [ -e "/usr/bin/python2.7" ]; then + run_python = "/usr/bin/python2.7" + elif [ -e "/usr/bin/python3" ]; then + run_python = "/usr/bin/python3" + elif [ -e "/usr/bin/python3.10" ]; then + run_python = "/usr/bin/python3.10" + elif [ -e "/usr/bin/python3.5" ]; then + run_python = "/usr/bin/python3.5" + fi + $run_python $data_analysis --$1 -s -f $logfile $threshold_arg fi } -- Gitee From e4e661d3cabf4c5b3fda50433b8ee1ee56e6c68a Mon Sep 17 00:00:00 2001 From: "guangshui.li" Date: Fri, 2 Sep 2022 15:00:52 +0800 Subject: [PATCH 4/4] iosdiag: Fix error 'run_python: command not found' Signed-off-by: guangshui.li --- source/tools/combine/iosdiag/entry/iosdiag.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/source/tools/combine/iosdiag/entry/iosdiag.sh b/source/tools/combine/iosdiag/entry/iosdiag.sh index 1aa5d28b..25556f94 100755 --- a/source/tools/combine/iosdiag/entry/iosdiag.sh +++ b/source/tools/combine/iosdiag/entry/iosdiag.sh @@ -43,19 +43,19 @@ upload_data() { datafile_analysis() { if [ -e "$logfile" ] then - run_python = "python" + run_python="python" if [ -e "/usr/bin/python" ]; then - run_python = "/usr/bin/python" + run_python="/usr/bin/python" elif [ -e "/usr/bin/python2" ]; then - run_python = "/usr/bin/python2" + run_python="/usr/bin/python2" elif [ -e "/usr/bin/python2.7" ]; then - run_python = "/usr/bin/python2.7" + run_python="/usr/bin/python2.7" elif [ -e "/usr/bin/python3" ]; then - run_python = "/usr/bin/python3" + run_python="/usr/bin/python3" elif [ -e "/usr/bin/python3.10" ]; then - run_python = "/usr/bin/python3.10" + run_python="/usr/bin/python3.10" elif [ -e "/usr/bin/python3.5" ]; then - run_python = "/usr/bin/python3.5" + run_python="/usr/bin/python3.5" fi $run_python $data_analysis --$1 -s -f $logfile $threshold_arg fi -- Gitee