blob: a1aac0ba3c32e5ecafae704dcc132ad7a862fe33 [file] [log] [blame]
import os
import re
from typing import TextIO
import multiprocessing as mp
import time
def CollateErrors(sourceLocation: str, outputLocation: str) -> None:
macrosPaths = [f.path for f in os.scandir(sourceLocation) if f.is_dir()]
processes = [mp.Process(target=CheckMacro, args=(macroPath, outputLocation)) for macroPath in macrosPaths]
[process.start() for process in processes]
[process.join() for process in processes]
def CheckMacro(macroPath: str, outputLocation: str) -> None:
outputTypes = ["logs", "reports"]
outputSections = ["synthesis", "routing", "placement", "floorplan", "finishing"]
macroName = os.path.basename(macroPath)
buildPath = os.path.join(macroPath, "runs", macroName)
macroOutputPath = os.path.join(outputLocation, macroName)
if not os.path.exists(macroOutputPath):
os.mkdir(macroOutputPath)
errorOutputFilePath = os.path.join(macroOutputPath, "errors.log")
if os.path.exists(errorOutputFilePath):
os.remove(errorOutputFilePath)
warningOutputFilePath = os.path.join(macroOutputPath, "warnings.log")
if os.path.exists(warningOutputFilePath):
os.remove(warningOutputFilePath)
errorCount = 0
warningCount = 0
violationCount = 0
errorOutputFile = None
warningOutputFile = None
try:
errorOutputFile = open(errorOutputFilePath, "a")
warningOutputFile = open(warningOutputFilePath, "a")
if os.path.exists(buildPath):
# Copy errors from file
errorFilePath = os.path.join(buildPath, "errors.log")
if os.path.exists(errorFilePath):
with open(errorFilePath, "r") as f:
lines = f.readlines()
errorOutputFile.writelines(lines)
errorCount += len(lines)
# Copy warnings from file
warningFilePath = os.path.join(buildPath, "warnings.log")
if os.path.exists(warningFilePath):
with open(warningFilePath, "r") as f:
lines = f.readlines()
warningOutputFile.writelines(lines)
warningCount += len(lines)
for dir in outputTypes:
for section in outputSections:
path = os.path.join(buildPath, dir, section)
files = [f.path for f in os.scandir(path) if f.is_file() and (f.path.endswith(".log") or f.path.endswith(".rpt"))]
for file in files:
e, w, v = CheckFile(file, errorOutputFile, warningOutputFile)
errorCount += e
warningCount += w
violationCount += v
finally:
if errorOutputFile is not None:
errorOutputFile.close()
if warningOutputFile is not None:
warningOutputFile.close()
print(f"Checking macro '{macroName}': ", end="")
if errorCount == 0 and violationCount == 0 and warningCount == 0:
if os.path.exists(buildPath):
print("Ok")
else:
print("No runs")
else:
print("Found issues")
if errorCount != 0:
print(f" \033[91mErrors: {errorCount}\033[0m")
if violationCount != 0:
print(f" \033[91mViolations: {violationCount}\033[0m")
if warningCount != 0:
print(f" \033[93mWarnings: {warningCount}\033[0m")
def CheckFile(fileName: str, errorFile: TextIO, warningFile: TextIO) -> tuple[int, int, int]:
if not os.path.exists(fileName):
return 0, 0, 0
errorCount = 0
warningCount = 0
violationCount = 0
with open(fileName, "r") as f:
lines = f.readlines()
for i, line in enumerate(lines):
if re.search("(?<![_\\-.\\w])error(?![_\\-.\\w])", line, re.IGNORECASE) is not None:
errorFile.write(f"{fileName}[{i}]: {line.strip()}\n")
errorCount += 1
elif re.search("(?<![_\\-.\\w])violated(?![_\\-.\\w])", line, re.IGNORECASE) is not None:
errorFile.write(f"{fileName}[{i}]: {line.strip()}\n")
violationCount += 1
elif "has no liberty cell." not in line and "Parent cell lists instance of" not in line and "Character in instance name converted to underscore." not in line and "is a placeholder, treated as a black box." not in line and "[WARNING GRT-" not in line and "[WARNING TAP-" not in line and "[WARNING ORD-" not in line and "[WARNING STA-" not in line and "[WARNING IFP-" not in line and "[WARNING PSM-" not in line:
if re.search("(?<![_\\-.\\w])warning(?![_\\-.\\w])", line, re.IGNORECASE) is not None:
warningFile.write(f"{fileName}[{i}]: {line.strip()}\n")
warningCount += 1
return errorCount, warningCount, violationCount
def main():
CollateErrors("openlane/", "docs/Logs/")
if __name__ == "__main__":
main()