dmlc--dgl
eae6ce2a4f
* Creating ParMETIS wrapper script to run parmetis using one script from user perspective * Addressed all the CI comments from PR https://github.com/dmlc/dgl/pull/4529 * Addressing CI comments. * Isort, and black changes. * Replaced python with python3 * Replaced single quote with double quotes per suggestion. * Removed print statement * Addressing CI Commets. * Addressing CI review comments. * Addressing CI comments as per chime discussion with Rui * CI Comments, Black and isort changes * Align with code refactoring, black, isort and code review comments. * Addressing CI review comments, and fixing merge issues with the master branch * Updated with proper unit test skip decorator
157 行
4.8 KiB
Python
157 行
4.8 KiB
Python
import argparse
|
|
import logging
|
|
import os
|
|
import platform
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import constants
|
|
from utils import read_json
|
|
|
|
|
|
def check_dependencies():
|
|
"""Check if all the dependencies needed for the execution of this file
|
|
are installed.
|
|
"""
|
|
|
|
exec_path = os.get_exec_path()
|
|
mpi_install = False
|
|
for x in exec_path:
|
|
if os.path.isfile(os.path.join(x, "mpirun")):
|
|
mpi_install = True
|
|
break
|
|
assert (
|
|
mpi_install
|
|
), "Could not locate the following dependency: MPI. Please install it and try again."
|
|
|
|
|
|
def run_parmetis_wrapper(params):
|
|
"""Function to execute all the steps needed to run ParMETIS
|
|
|
|
Parameters:
|
|
-----------
|
|
params : argparser object
|
|
an instance of argparser class to capture command-line arguments
|
|
"""
|
|
assert os.path.isfile(params.schema_file)
|
|
assert os.path.isfile(params.hostfile)
|
|
|
|
schema = read_json(params.schema_file)
|
|
graph_name = schema[constants.STR_GRAPH_NAME]
|
|
num_partitions = len(schema[constants.STR_NUM_NODES_PER_CHUNK][0])
|
|
|
|
# Check if parmetis_preprocess.py exists.
|
|
assert os.path.isfile(
|
|
os.path.join(
|
|
os.path.dirname(os.path.abspath(__file__)), "parmetis_preprocess.py"
|
|
)
|
|
), "Please check DGL Installation, parmetis_preprocess.py file does not exist."
|
|
|
|
# Trigger pre-processing step to generate input files for ParMETIS.
|
|
preproc_cmd = (
|
|
f"mpirun -np {num_partitions} -hostfile {params.hostfile} "
|
|
f"python3 tools/distpartitioning/parmetis_preprocess.py "
|
|
f"--schema_file {params.schema_file} "
|
|
f"--output_dir {params.preproc_output_dir}"
|
|
)
|
|
logging.info(f"Executing Preprocessing Step: {preproc_cmd}")
|
|
os.system(preproc_cmd)
|
|
logging.info(f"Done Preprocessing Step")
|
|
|
|
# Trigger ParMETIS for creating metis partitions for the input graph.
|
|
parmetis_install_path = "pm_dglpart3"
|
|
if params.parmetis_install_path is not None:
|
|
parmetis_install_path = os.path.join(
|
|
params.parmetis_install_path, parmetis_install_path
|
|
)
|
|
parmetis_nfiles = os.path.join(
|
|
params.preproc_output_dir, "parmetis_nfiles.txt"
|
|
)
|
|
parmetis_efiles = os.path.join(
|
|
params.preproc_output_dir, "parmetis_efiles.txt"
|
|
)
|
|
parmetis_cmd = (
|
|
f"mpirun -np {num_partitions} -hostfile {params.hostfile} "
|
|
f"{parmetis_install_path} {graph_name} {num_partitions} "
|
|
f"{parmetis_nfiles} {parmetis_efiles}"
|
|
)
|
|
logging.info(f"Executing ParMETIS: {parmetis_cmd}")
|
|
os.system(parmetis_cmd)
|
|
logging.info(f"Done ParMETIS execution step")
|
|
|
|
# Trigger post-processing step to convert parmetis output to the form
|
|
# acceptable by dist. graph partitioning pipeline.
|
|
parmetis_output_file = os.path.join(
|
|
os.getcwd(), f"{graph_name}_part.{num_partitions}"
|
|
)
|
|
postproc_cmd = (
|
|
f"python3 tools/distpartitioning/parmetis_postprocess.py "
|
|
f"--schema_file {params.schema_file} "
|
|
f"--parmetis_output_file {parmetis_output_file} "
|
|
f"--partitions_dir {params.partitions_dir}"
|
|
)
|
|
logging.info(f"Executing PostProcessing: {postproc_cmd}")
|
|
os.system(postproc_cmd)
|
|
logging.info("Done Executing ParMETIS...")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
"""Main function to invoke the parmetis wrapper function"""
|
|
parser = argparse.ArgumentParser(
|
|
description="Run ParMETIS as part of the graph partitioning pipeline"
|
|
)
|
|
# Preprocessing step.
|
|
parser.add_argument(
|
|
"--schema_file",
|
|
required=True,
|
|
type=str,
|
|
help="The schema of the input graph",
|
|
)
|
|
parser.add_argument(
|
|
"--preproc_output_dir",
|
|
required=True,
|
|
type=str,
|
|
help="The output directory for the node weights files and auxiliary\
|
|
files for ParMETIS.",
|
|
)
|
|
parser.add_argument(
|
|
"--hostfile",
|
|
required=True,
|
|
type=str,
|
|
help="A text file with a list of ip addresses.",
|
|
)
|
|
|
|
# ParMETIS step.
|
|
parser.add_argument(
|
|
"--parmetis_install_path",
|
|
required=False,
|
|
type=str,
|
|
help="The directory where ParMETIS is installed",
|
|
)
|
|
|
|
# Postprocessing step.
|
|
parser.add_argument(
|
|
"--parmetis_output_file",
|
|
required=True,
|
|
type=str,
|
|
help="ParMETIS output file (global_node_id to partition_id mappings)",
|
|
)
|
|
parser.add_argument(
|
|
"--partitions_dir",
|
|
required=True,
|
|
type=str,
|
|
help="The directory where the files (with metis partition ids) grouped \
|
|
by node_types",
|
|
)
|
|
params = parser.parse_args()
|
|
|
|
# Configure logging.
|
|
logging.basicConfig(
|
|
level="INFO",
|
|
format=f"[{platform.node()} \
|
|
%(levelname)s %(asctime)s PID:%(process)d] %(message)s",
|
|
)
|
|
|
|
check_dependencies()
|
|
run_parmetis_wrapper(params)
|