Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 2.3.0 #410

Merged
merged 11 commits into from
Sep 27, 2023
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ jobs:
run: python -m mypy --config-file=mypy.ini -p discopop_wizard

- name: "Check formatting of DiscoPoP Explorer"
run: python -m black -l 100 --check discopop_explorer
run: python -m black -l 120 --check discopop_explorer

- name: "Check formatting of DiscoPoP Library"
run: python -m black -l 100 --check discopop_library
run: python -m black -l 120 --check discopop_library

- name: "Check formatting of DiscoPoP Profiler"
run: python -m black -l 100 --check discopop_profiler
run: python -m black -l 120 --check discopop_profiler

- name: "Check formatting of DiscoPoP Wizard"
run: python -m black -l 100 --check discopop_wizard
run: python -m black -l 120 --check discopop_wizard

- name: Test DiscoPop Explorer - DISABLED
run: |
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ repos:
rev: 23.7.0
hooks:
- id: black # run black fromatter on all files
args: [--line-length=100]
args: [--line-length=120]


- repo: local
Expand Down
159 changes: 39 additions & 120 deletions discopop_explorer/PETGraphX.py

Large diffs are not rendered by default.

12 changes: 3 additions & 9 deletions discopop_explorer/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,7 @@ def parse_args() -> ExplorerArguments:
arguments = parser.parse_args()

# ensure that --cu-inst-res and --llvm-cxxfilt-path are set if --task-pattern is set
if arguments.task_pattern and (
arguments.cu_inst_res is None or arguments.llvm_cxxfilt_path is None
):
if arguments.task_pattern and (arguments.cu_inst_res is None or arguments.llvm_cxxfilt_path is None):
parser.error("--task-pattern requires --cu-inst-res and --llvm-cxxfilt-path to be set")

# ensure that --cu-xml, --dep-file, --loop-counter, --reduction are set if --generate-data-cu-inst is set
Expand All @@ -120,14 +118,10 @@ def parse_args() -> ExplorerArguments:
arguments.fmap = get_path(arguments.path, arguments.fmap)
arguments.json = get_path_or_none(arguments.path, arguments.json)
arguments.cu_inst_res = get_path_or_none(arguments.path, arguments.cu_inst_res)
arguments.generate_data_cu_inst = get_path_or_none(
arguments.path, arguments.generate_data_cu_inst
)
arguments.generate_data_cu_inst = get_path_or_none(arguments.path, arguments.generate_data_cu_inst)
arguments.profiling = get_path_or_none(arguments.path, arguments.profiling)
arguments.dump_pet = get_path_or_none(arguments.path, arguments.dump_pet)
arguments.dump_detection_result = get_path_or_none(
arguments.path, arguments.dump_detection_result
)
arguments.dump_detection_result = get_path_or_none(arguments.path, arguments.dump_detection_result)
arguments.microbench_file = get_path_or_none(arguments.path, arguments.microbench_file)

return ExplorerArguments(
Expand Down
21 changes: 10 additions & 11 deletions discopop_explorer/discopop_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,26 @@
# directory for details.

import cProfile
from dataclasses import dataclass
from pathlib import Path
from pluginbase import PluginBase # type:ignore
from typing import List, Optional

import json
import os
import pstats2 # type:ignore
import sys
import time
from dataclasses import dataclass
from pathlib import Path
from typing import List, Optional

from .json_serializer import PatternInfoSerializer
from .parser import parse_inputs
from .pattern_detection import PatternDetectorX
from .PETGraphX import PETGraphX
import pstats2 # type:ignore
from pluginbase import PluginBase # type:ignore

from discopop_library.PathManagement.PathManagement import get_path
from discopop_library.discopop_optimizer.Microbench.ExtrapInterpolatedMicrobench import (
ExtrapInterpolatedMicrobench,
)
from discopop_library.PathManagement.PathManagement import get_path
from discopop_library.result_classes.DetectionResult import DetectionResult
from .PETGraphX import PETGraphX
from .json_serializer import PatternInfoSerializer
from .parser import parse_inputs
from .pattern_detection import PatternDetectorX


@dataclass
Expand Down
25 changes: 6 additions & 19 deletions discopop_explorer/generate_Data_CUInst.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
EdgeType,
)
from .parser import parse_inputs
from discopop_library.PathManagement.PathManagement import get_path


def __collect_children_ids(pet: PETGraphX, parent_id: NodeID, children_ids: List[NodeID]):
Expand Down Expand Up @@ -51,9 +50,7 @@ def __recursive_call_inside_loop(pet: PETGraphX, recursive_function_call: str) -
return False


def __recursive_function_called_multiple_times_inside_function(
pet: PETGraphX, recursive_function_call: str
) -> bool:
def __recursive_function_called_multiple_times_inside_function(pet: PETGraphX, recursive_function_call: str) -> bool:
"""checks if the given recursive function is called multiple times from within a functions body
:param pet: PET Graph
:param recursive_function_call: string representation of a recursive function call, extracted from cu-xml
Expand Down Expand Up @@ -143,9 +140,7 @@ def __search_recursive_calls(pet: PETGraphX, output_file, node: Node):
# check if recursive function call occurs inside loop (check if line contained in lines of any loop cu)
contained_in_loop = __recursive_call_inside_loop(pet, recursive_function_call)
# check if recursive function call is called multiple times
called_multiple_times = __recursive_function_called_multiple_times_inside_function(
pet, recursive_function_call
)
called_multiple_times = __recursive_function_called_multiple_times_inside_function(pet, recursive_function_call)

# check if recursive function is called inside loop or multiple times
if not (contained_in_loop or called_multiple_times):
Expand All @@ -163,15 +158,9 @@ def __search_recursive_calls(pet: PETGraphX, output_file, node: Node):
# node type is not cu so goto next node
if not isinstance(pet.node_at(child_id), CUNode):
continue
__output_dependencies_of_type(
pet, child_id, children_ids, output_file, DepType.RAW, "|RAW|"
)
__output_dependencies_of_type(
pet, child_id, children_ids, output_file, DepType.WAR, "|WAR|"
)
__output_dependencies_of_type(
pet, child_id, children_ids, output_file, DepType.WAW, "|WAW|"
)
__output_dependencies_of_type(pet, child_id, children_ids, output_file, DepType.RAW, "|RAW|")
__output_dependencies_of_type(pet, child_id, children_ids, output_file, DepType.WAR, "|WAR|")
__output_dependencies_of_type(pet, child_id, children_ids, output_file, DepType.WAW, "|WAW|")

output_file.write("\n")

Expand All @@ -189,9 +178,7 @@ def cu_instantiation_input_cpp(pet: PETGraphX, output_file: str):
def wrapper(cu_xml, dep_file, loop_counter_file, reduction_file, output_file):
"""Wrapper to generate the Data_CUInst.txt file, required for the generation of CUInstResult.txt"""
# 1. generate PET Graph
pet = PETGraphX.from_parsed_input(
*parse_inputs(cu_xml, dep_file, loop_counter_file, reduction_file)
)
pet = PETGraphX.from_parsed_input(*parse_inputs(cu_xml, dep_file, loop_counter_file, reduction_file))
# 2. Generate Data_CUInst.txt
cu_instantiation_input_cpp(pet, output_file)

Expand Down
7 changes: 4 additions & 3 deletions discopop_explorer/json_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
# directory for details.

from json import JSONEncoder
from typing import Dict, Any

from .PETGraphX import Node
from discopop_library.result_classes.DetectionResult import DetectionResult
from .PETGraphX import Node
from .pattern_detectors.PatternInfo import PatternInfo
from .pattern_detectors.pipeline_detector import PipelineStage
from .variable import Variable
from .pattern_detectors.task_parallelism.classes import TPIType
from .variable import Variable


def filter_members(d: dict) -> dict:
def filter_members(d: Dict[Any, Any]) -> Dict[Any, Any]:
"""Removes private and protected members (which starts with '_')

:param d: member dictionary
Expand Down
17 changes: 6 additions & 11 deletions discopop_explorer/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
# the 3-Clause BSD License. See the LICENSE file in the package base
# directory for details.

from dataclasses import dataclass
import re
import os
from typing import Any, List, Tuple
import re
import warnings
from collections import defaultdict
from dataclasses import dataclass
from os.path import abspath, dirname
from typing import Any, List, Tuple

from lxml import objectify # type:ignore

Expand Down Expand Up @@ -116,8 +116,7 @@ def __parse_dep_file(dep_fd, output_path: str) -> Tuple[List[DependenceItem], Li
static_dependency_lines = []
if not os.path.exists(os.path.join(output_path, "static_dependencies.txt")):
warnings.warn(
"Static dependencies could not be found under: "
+ os.path.join(output_path, "static_dependencies.txt")
"Static dependencies could not be found under: " + os.path.join(output_path, "static_dependencies.txt")
)
# todo
warnings.warn(
Expand Down Expand Up @@ -165,9 +164,7 @@ def __parse_dep_file(dep_fd, output_path: str) -> Tuple[List[DependenceItem], Li
else:
# compatibility with results created without alias analysis
var_name = var_str
dependencies_list.append(
DependenceItem(sink, source_fields[0], type, var_name, aa_var_name)
)
dependencies_list.append(DependenceItem(sink, source_fields[0], type, var_name, aa_var_name))

return dependencies_list, loop_data_list

Expand Down Expand Up @@ -210,9 +207,7 @@ def parse_inputs(cu_file, dependencies, reduction_file, file_mapping):


def is_reduction(reduction_line, fmap_lines, file_mapping):
rex = re.compile(
"FileID : ([0-9]*) Loop Line Number : [0-9]* Reduction Line Number : ([0-9]*) "
)
rex = re.compile("FileID : ([0-9]*) Loop Line Number : [0-9]* Reduction Line Number : ([0-9]*) ")
if not rex:
return False
res = rex.search(reduction_line)
Expand Down
25 changes: 9 additions & 16 deletions discopop_explorer/pattern_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
# This software may be modified and distributed under the terms of
# the 3-Clause BSD License. See the LICENSE file in the package base
# directory for details.
import os
import sys
from typing import Dict, Union

from alive_progress import alive_bar # type: ignore

from discopop_explorer.pattern_detectors.task_parallelism.task_parallelism_detector import (
build_preprocessed_graph_and_run_detection as detect_tp,
)
from discopop_library.discopop_optimizer.OptimizationGraph import OptimizationGraph
from discopop_library.discopop_optimizer.Variables.Experiment import Experiment
from discopop_library.discopop_optimizer.classes.system.System import System
Expand All @@ -20,13 +23,9 @@
from .PETGraphX import DummyNode, LoopNode, PETGraphX, EdgeType
from .pattern_detectors.do_all_detector import run_detection as detect_do_all
from .pattern_detectors.geometric_decomposition_detector import run_detection as detect_gd
from .pattern_detectors.simple_gpu_patterns.gpu_pattern_detector import run_detection as detect_gpu
from .pattern_detectors.pipeline_detector import run_detection as detect_pipeline
from .pattern_detectors.reduction_detector import run_detection as detect_reduction
from discopop_explorer.pattern_detectors.task_parallelism.task_parallelism_detector import (
build_preprocessed_graph_and_run_detection as detect_tp,
)
from alive_progress import alive_bar # type: ignore
from .pattern_detectors.simple_gpu_patterns.gpu_pattern_detector import run_detection as detect_gpu


class PatternDetectorX(object):
Expand Down Expand Up @@ -142,17 +141,11 @@ def __identify_scheduling_clauses(
arguments_1,
)
arguments_2 = {"--exhaustive-search": False, "--headless-mode": True}
optimization_graph = OptimizationGraph(
project_folder_path, experiment, arguments_2, None, False
)
optimization_graph = OptimizationGraph(project_folder_path, experiment, arguments_2, None, False)

for do_all_suggestion in res.do_all:
for node_id in get_nodes_from_cu_id(
experiment.optimization_graph, do_all_suggestion.node_id
):
workload_delta, min_workload, max_workload = get_workload_delta_for_cu_node(
experiment, node_id
)
for node_id in get_nodes_from_cu_id(experiment.optimization_graph, do_all_suggestion.node_id):
workload_delta, min_workload, max_workload = get_workload_delta_for_cu_node(experiment, node_id)
print(
"DOALL @ ",
do_all_suggestion.node_id,
Expand Down
20 changes: 5 additions & 15 deletions discopop_explorer/pattern_detectors/PatternInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import json
from typing import Optional

from ..utils import calculate_workload, calculate_per_iteration_workload_of_loop
from ..PETGraphX import LoopNode, Node, NodeID, LineID, PETGraphX
from ..utils import calculate_workload, calculate_per_iteration_workload_of_loop


class PatternInfo(object):
Expand All @@ -25,9 +25,7 @@ class PatternInfo(object):
instructions_count: Optional[int]
workload: Optional[int]
per_iteration_workload: Optional[int]
dp_optimizer_device_id: Optional[
int
] = None # used by discopop_optimizer. unused by discopop_explorer.
dp_optimizer_device_id: Optional[int] = None # used by discopop_optimizer. unused by discopop_explorer.

def __init__(self, node: Node):
"""
Expand All @@ -43,15 +41,9 @@ def __init__(self, node: Node):
else -1
)
self.iterations_count = (
node.loop_data.total_iteration_count
if (isinstance(node, LoopNode) and node.loop_data is not None)
else -1
)
self.entries = (
node.loop_data.entry_count
if (isinstance(node, LoopNode) and node.loop_data is not None)
else -1
node.loop_data.total_iteration_count if (isinstance(node, LoopNode) and node.loop_data is not None) else -1
)
self.entries = node.loop_data.entry_count if (isinstance(node, LoopNode) and node.loop_data is not None) else -1

# TODO self.instructions_count = total_instructions_count(pet, node)
self.workload = None
Expand All @@ -65,9 +57,7 @@ def to_json(self):
if key.startswith("_"):
del dic[key]

return json.dumps(
dic, indent=2, default=lambda o: o.toJSON()
) # , default=lambda o: "<not serializable>")
return json.dumps(dic, indent=2, default=lambda o: o.toJSON()) # , default=lambda o: "<not serializable>")

def get_workload(self, pet: PETGraphX) -> int:
"""returns the workload of self._node"""
Expand Down
Loading