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

Added analysis command and json output (Single commit Release version) #76

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ You just need to use `deepview memory` instead of `deepview time`.
python3 -m deepview_profile memory entry_point.py --output my_output_file.sqlite
```

To export various available analysis to json file, you may use `deepview analysis --all` command for exact entry point and output file. It is required to later view the analysis on the web viewer.

It is also possible to run several optional analysis. There are such analysis available: `--measure-breakdown`, `--measure-throughput`, `--habitat-predict`, `--measure-utilization`, `--energy-compute`, `--exclude-source`

```zsh
python3 -m deepview_profile analysis entry_point.py --all --exclude-source --output=complete_analysis.json
```

`--exclude-source` option allows not adding `encodedFiles` section to output, that is available for `--measure-breakdown` analysis

or various combinations of optional analysis

```zsh
python3 -m deepview_profile analysis entry_point.py --measure-breakdown --measure-throughput --habitat-predict --measure-utilization --energy-compute --output=various_analysis.json
```

<h2 id="dev-setup">Development Environment Setup</h2>

From the project root, do
Expand Down
2 changes: 2 additions & 0 deletions deepview_profile/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import deepview_profile.commands.interactive
import deepview_profile.commands.memory
import deepview_profile.commands.time
import deepview_profile.commands.analysis


def main():
Expand All @@ -25,6 +26,7 @@ def main():
deepview_profile.commands.interactive.register_command(subparsers)
deepview_profile.commands.memory.register_command(subparsers)
deepview_profile.commands.time.register_command(subparsers)
deepview_profile.commands.analysis.register_command(subparsers)
args = parser.parse_args()

if args.version:
Expand Down
177 changes: 177 additions & 0 deletions deepview_profile/commands/analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import logging
import os
import sys
import json
import platform

from deepview_profile.analysis.runner import analyze_project
from deepview_profile.nvml import NVML
from deepview_profile.utils import release_memory, next_message_to_dict, files_encoded_unique

from deepview_profile.initialization import (
check_skyline_preconditions,
initialize_skyline,
)
from deepview_profile.error_printing import print_analysis_error

logger = logging.getLogger(__name__)

def register_command(subparsers):
parser = subparsers.add_parser(
"analysis",
help="Generate usage report for various analysis.",
)
parser.add_argument(
"entry_point",
help="The entry point file in this project that contains the DeepView "
"provider functions."
)
parser.add_argument(
"--all",
action="store_true",
help="The complete analysis of all methods"
)
parser.add_argument(
"-breakdown", "--measure-breakdown",
action="store_true",
help="Adds breakdown data to results"
)
parser.add_argument(
"-throughput", "--measure-throughput",
action="store_true",
help="Adds throughput data to results"
)
parser.add_argument(
"-predict", "--habitat-predict",
action="store_true",
help="Adds habitat data prediction to results"
)
parser.add_argument(
"-utilization", "--measure-utilization",
action="store_true",
help="Adds utilization data to results"
)
parser.add_argument(
"-energy", "--energy-compute",
action="store_true",
help="Adds energy use to results"
)
parser.add_argument(
"-o", "--output",
help="The location where the complete report should be stored",
required=True
)
parser.add_argument(
"--log-file",
help="The location of the log file",
)
parser.add_argument(
"--exclude-source",
action="store_true",
help="Allows not adding encodedFiles section"
)
parser.add_argument("--debug", action="store_true", help="Log debug messages.")
parser.set_defaults(func=main)

def measure_breakdown(session, nvml):
print("analysis: running measure_breakdown()")
yield session.measure_breakdown(nvml)
release_memory()

def measure_throughput(session):
print("analysis: running measure_throughput()")
yield session.measure_throughput()
release_memory()

def habitat_predict(session):
print("analysis: running deepview_predict()")
yield session.habitat_predict()
release_memory()

def measure_utilization(session):
print("analysis: running measure_utilization()")
yield session.measure_utilization()
release_memory()

def energy_compute(session):
print("analysis: running energy_compute()")
yield session.energy_compute()
release_memory()

def hardware_information(nvml):

hardware_info = {
'hostname': platform.node(),
'os': " ".join(list(platform.uname())),
'gpus': nvml.get_device_names()
}
return hardware_info

def actual_main(args):
OlegGolfer7 marked this conversation as resolved.
Show resolved Hide resolved
from deepview_profile.analysis.session import AnalysisSession
from deepview_profile.exceptions import AnalysisError

if os.path.exists(args.output):
print(
"ERROR: The specified output file already exists.",
file=sys.stderr,
)
sys.exit(1)

try:
project_root = os.getcwd()
data = {
"analysisState": {
"message_type": "analysis",
"project_root": project_root,
"project_entry_point": args.entry_point,
"hardware_info": {},
"throughput": {},
"breakdown": {},
"habitat": {},
"additionalProviders": "",
"energy": {},
"utilization": {}
},
"epochs": 50,
"iterPerEpoch": 1000,
"encodedFiles": []
}

session = AnalysisSession.new_from(project_root, args.entry_point)
release_memory()

is_return_all = args.all

with NVML() as nvml:
data['analysisState']['hardware_info'] = hardware_information(nvml)
if args.measure_breakdown or is_return_all:
data['analysisState']['breakdown'] = next_message_to_dict(measure_breakdown(session, nvml))

operation_tree = data['analysisState']['breakdown']['operationTree']
if not args.exclude_source and operation_tree is not None:
data['encodedFiles'] = files_encoded_unique(operation_tree)

if args.measure_throughput or is_return_all:
data['analysisState']['throughput'] = next_message_to_dict(measure_throughput(session))

if args.habitat_predict or is_return_all:
data['analysisState']['habitat'] = next_message_to_dict(habitat_predict(session))

if args.measure_utilization or is_return_all:
data['analysisState']['utilization'] = next_message_to_dict(measure_utilization(session))

if args.energy_compute or is_return_all:
data['analysisState']['energy'] = next_message_to_dict(energy_compute(session))

with open(args.output, "w") as json_file:
json.dump(data, json_file, indent=4)

except AnalysisError as ex:
print_analysis_error(ex)
sys.exit(1)

def main(args):
check_skyline_preconditions(args)
initialize_skyline(args)
actual_main(args)
9 changes: 9 additions & 0 deletions deepview_profile/nvml.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ def get_memory_capacity(self):
# TODO: Support multiple devices
handle = pynvml.nvmlDeviceGetHandleByIndex(0)
return pynvml.nvmlDeviceGetMemoryInfo(handle)

def get_device_names(self):
device_names = []
for i in range(pynvml.nvmlDeviceGetCount()):
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
device_name = pynvml.nvmlDeviceGetName(handle).decode("utf-8")
device_names.append(device_name)
return device_names

43 changes: 42 additions & 1 deletion deepview_profile/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,51 @@
import torch
import logging
import gc
import os
import base64

from google.protobuf.json_format import MessageToDict

logger = logging.getLogger(__name__)

def release_memory():
logger.debug("Emptying cache")
gc.collect()
torch.cuda.empty_cache()
torch.cuda.empty_cache()

def next_message_to_dict(object):
message = next(object)
return MessageToDict(message)

OlegGolfer7 marked this conversation as resolved.
Show resolved Hide resolved
def files_encoded_unique(operation_tree):
encoded_files = []

for analysis in operation_tree:
context_info_map = analysis['operation'].get('contextInfoMap', None)
if context_info_map is not None and len(context_info_map) > 0:
filename = list(context_info_map[0]['context']['filePath']['components']).pop()

already_in_list = next((item for item in encoded_files if item['name'] == filename), None)
if not already_in_list:
file_path = os.path.join("", *list(context_info_map[0]['context']['filePath']['components']))

encoded_file = encode_file("", file_path)
encoded_files.append(encoded_file)

return encoded_files

def encode_file(root, file):
file_dict = None
if os.path.splitext(file)[1] == ".py" and file != "entry_point.py":
file_dict = {
"name": file,
"content": ""
}

filename = os.path.join(root, file)

with open(filename, "r") as f:
file_content = f.read()
file_dict["content"] = base64.b64encode(file_content.encode("utf-8")).decode("utf-8")

return file_dict