| #!/usr/bin/env python3 | 
 | # -*- coding: utf-8 -*- | 
 | # | 
 | # Copyright (C) 2017-2020  The Project X-Ray Authors. | 
 | # | 
 | # Use of this source code is governed by a ISC-style | 
 | # license that can be found in the LICENSE file or at | 
 | # https://opensource.org/licenses/ISC | 
 | # | 
 | # SPDX-License-Identifier: ISC | 
 | import shutil | 
 | import sys | 
 | import subprocess | 
 | from multiprocessing import Pool | 
 | from itertools import chain | 
 | import argparse | 
 |  | 
 | # Can be used to redirect vivado tons of output | 
 | # stdout=DEVNULL in subprocess.check_call | 
 |  | 
 |  | 
 | # Worker function called from threads | 
 | def start_tiles(argList): | 
 |     blockID, start, stop, total = argList | 
 |     print("Running instance :" + str(blockID) + " / " + str(total)) | 
 |     subprocess.check_call( | 
 |         "${XRAY_VIVADO} -mode batch -source $FUZDIR/jobtiles.tcl -tclargs " + | 
 |         str(blockID) + " " + str(start) + " " + str(stop), | 
 |         shell=True) | 
 |  | 
 |  | 
 | def start_nodes(argList): | 
 |     blockID, start, stop, total = argList | 
 |     print("Running instance :" + str(blockID) + " / " + str(total)) | 
 |     subprocess.check_call( | 
 |         "${XRAY_VIVADO} -mode batch -source $FUZDIR/jobnodes.tcl -tclargs " + | 
 |         str(blockID) + " " + str(start) + " " + str(stop), | 
 |         shell=True) | 
 |  | 
 |  | 
 | # Function called once to get the total numbers of tiles to list | 
 | def get_nb_tiles(): | 
 |     print("Fetching total number of tiles") | 
 |     subprocess.check_call( | 
 |         "${XRAY_VIVADO} -mode batch -source $FUZDIR/get_tilescount.tcl", | 
 |         shell=True) | 
 |     countfile = open("nb_tiles.txt", "r") | 
 |     return int(countfile.readline()) | 
 |  | 
 |  | 
 | def get_nb_nodes(): | 
 |     print("Fetching total number of nodes") | 
 |     subprocess.check_call( | 
 |         "${XRAY_VIVADO} -mode batch -source $FUZDIR/get_nodescount.tcl", | 
 |         shell=True) | 
 |     countfile = open("nb_nodes.txt", "r") | 
 |     return int(countfile.readline()) | 
 |  | 
 |  | 
 | def run_pool(itemcount, nbBlocks, blocksize, nbParBlock, workFunc): | 
 |     # We handle the case of not integer multiple of pips | 
 |     intitemcount = blocksize * nbBlocks | 
 |     lastRun = False | 
 |     modBlocks = itemcount - intitemcount | 
 |     if modBlocks != 0: | 
 |         lastRun = True | 
 |         nbBlocks = nbBlocks + 1 | 
 |  | 
 |     print( | 
 |         "Items Count: " + str(itemcount) + " - Number of blocks: " + | 
 |         str(nbBlocks) + " - Parallel blocks: " + str(nbParBlock) + | 
 |         " - Blocksize: " + str(blocksize) + " - Modulo Blocks: " + | 
 |         str(modBlocks)) | 
 |  | 
 |     blockId = range(0, nbBlocks) | 
 |     startI = range(0, intitemcount, blocksize) | 
 |     stopI = range(blocksize, intitemcount + 1, blocksize) | 
 |     totalBlock = [nbBlocks for _ in range(nbBlocks)] | 
 |  | 
 |     # In case we have a last incomplete block we add it as a last | 
 |     # element in the arguments list | 
 |     if lastRun == True: | 
 |         startI = chain(startI, [intitemcount]) | 
 |         stopI = chain(stopI, [itemcount]) | 
 |  | 
 |     argList = zip(blockId, startI, stopI, totalBlock) | 
 |  | 
 |     with Pool(processes=nbParBlock) as pool: | 
 |         pool.map(workFunc, argList) | 
 |  | 
 |     return nbBlocks | 
 |  | 
 |  | 
 | # ========================================================================== | 
 | # ===== FPGA Logic Items data ============================================== | 
 | # For Artix 7 50T: | 
 | #   - Total pips: 22002368 | 
 | #   - Total tiles: 18055 | 
 | #   - Total nodes: 1953452 | 
 | # For Kintex 7 70T: | 
 | #   - Total pips: 29424910 | 
 | #   - Total tiles: 24453 | 
 | #   - Total nodes: 2663055 | 
 | # For Zynq 7 z010: | 
 | #   - Total pips: 12462138 | 
 | #   - Total tiles: 13440 | 
 | #   - Total nodes: 1122477 | 
 | # ========================================================================= | 
 | # Dividing by about 64 over 4 core is not optimized but a default to run | 
 | # on most computer | 
 | # ========================================================================= | 
 |  | 
 |  | 
 | def main(argv): | 
 |     parser = argparse.ArgumentParser() | 
 |     parser.add_argument( | 
 |         "-p", | 
 |         "--nbPar", | 
 |         help="Number of parallel instances of Vivado", | 
 |         type=int, | 
 |         default=4) | 
 |     parser.add_argument( | 
 |         "-t", | 
 |         "--sizeTilesBlock", | 
 |         help="Define the number of tiles to process per instance", | 
 |         type=int, | 
 |         default=300) | 
 |     parser.add_argument( | 
 |         "-n", | 
 |         "--sizeNodesBlock", | 
 |         help="Define the number of nodes to process per instance", | 
 |         type=int, | 
 |         default=30000) | 
 |     args = parser.parse_args() | 
 |  | 
 |     nbParBlock = args.nbPar | 
 |     blockTilesSize = args.sizeTilesBlock | 
 |     blockNodesSize = args.sizeNodesBlock | 
 |  | 
 |     print( | 
 |         " nbPar: " + str(nbParBlock) + " blockTilesSize: " + | 
 |         str(blockTilesSize) + " blockNodesSize: " + str(blockNodesSize)) | 
 |  | 
 |     tilescount = get_nb_tiles() | 
 |     nbTilesBlocks = int(tilescount / blockTilesSize) | 
 |  | 
 |     tilesFileCount = run_pool( | 
 |         tilescount, nbTilesBlocks, blockTilesSize, nbParBlock, start_tiles) | 
 |  | 
 |     nodescount = get_nb_nodes() | 
 |     nbNodesBlocks = int(nodescount / blockNodesSize) | 
 |  | 
 |     nodeFilesCount = run_pool( | 
 |         nodescount, nbNodesBlocks, blockNodesSize, nbParBlock, start_nodes) | 
 |  | 
 |     print("Generating final csv files") | 
 |  | 
 |     with open("root.csv", "w") as wfd: | 
 |         wfd.write("filetype,subtype,filename\n") | 
 |         for j in range(0, tilesFileCount): | 
 |             ftiles = "root_" + str(j) + ".csv" | 
 |             with open(ftiles, "r") as fd: | 
 |                 shutil.copyfileobj(fd, wfd) | 
 |         for j in range(0, nodeFilesCount): | 
 |             fnodes = "root_node_" + str(j) + ".csv" | 
 |             with open(fnodes, "r") as fd: | 
 |                 shutil.copyfileobj(fd, wfd) | 
 |  | 
 |     print("Work done !") | 
 |     return 0 | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     sys.exit(main(sys.argv)) |