Make Perf Test Configurable (#7836)

- Allow anyone to kick off a perf test here. Customize: branch, eps, model selection, cuda version.
- Only run shape inference when required.
- Kill errored out memory processes.
- Remove warmup run.
- Clean up script.
- Standalone_TRT is it's own "EP" vs as an additional run with TRT EP
This commit is contained in:
Olivia Jain 2021-06-18 11:11:19 -07:00 committed by GitHub
parent aa68157c3d
commit b2247ece25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 365 additions and 457 deletions

View file

@ -1,7 +1,21 @@
# TensorRT EP Performance Test Script
This script mainly focus on benchmarking ORT TensorRT EP performance compared with CUDA EP and standalone TensorRT. The metrics includes TensorRT EP performance gain, percentage of model operators and execution time that run on TensorRT EP.
## Usage
## Usage with Azure Pipelines
### Linux GPU TensorRT Perf CI Pipeline
- [x] **Build ORT** Build ORT from source. Specify _branch_ variable if not master.
- [x] **Post to Dashboard** Post to ONNX Runtime EP Dashboard (No Docker).
- [ ] **Run in Docker (CUDA 11.0)** Check to run in CUDA 11.0 vs 10.2 (default).
- [ ] **Configure EPs** Choose which EPs to run against. Specify _epList_ variable.
- **ModelGroups**: Select which model groups to run. (i.e. selected-models, specify _selected-models_ variable)
#### Variables (under Advanced Options)
- **branch**: (*default: master*) Specified branch to run against.
- **epList**: List of EPs to run separated by spaces [from available options](https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/python/tools/tensorrt/perf/benchmark.py#L26) _i.e. "CPUExecutionProvider TensorrtExecutionProvider"_
- **selected-models**: Specified path to model json file or model folder if selected-models in ModelGroups.
## Usage Locally
You can use following command to test whether models can be run using TensorRT and run benchmark:
```
./perf.sh
@ -16,6 +30,7 @@ python3 benchmark.py -r benchmark -i random -t 100
```
Please note that benchmark_wrapper.py creates one process to execute benchmark.py for every model and every ep, therefore, when process runs into segmentation fault and is forced to exit, the wrapper can catch the error.
However, benchmark.py creates only one process to run all the model inferences on all eps, once the process triggers segmentation fault, the whole process is forced to exit and can't successfully capture the error and testing results.
### Options
- **-r, --running_mode**: (*defaul: benchmark*) There are two types of running mode, *validate* and *benchmark*. For validation, this test script records any runtime error as well as validates the accuracy of prediction result using *np.testing.assert_almost_equal()* and exposes result that doesn't meet accuracy requirement. For benchmark, it simply runs model inference assuming model is correct and get the performance metrics. (Note: If you run validation first and then benchmark, test script knows which model has issue and will skip benchmarking of this particular model.)
- **-m, --model_source**: (*default: model_list.json*) There are two ways to specify list of models to test. (1) Explicitly specify model list file which contains model information. (2) Specify directory which has following layout:
@ -36,10 +51,12 @@ However, benchmark.py creates only one process to run all the model inferences o
```
- **-i, --input_data**: (*default: random*) Where is the input data coming from. The value are *zoo* or *random*. The input data can be from ONNX model zoo or it can be randomly generated by test script.
- **-t, --test_times**: (*default: 1*) Number of inference run when in 'benchmark' running mode.
- **-w, --workspace**: (*default: ./*) Root directory of perf dir. Tensorrt_home should be discoverable from this path.
- **-o, --perf_result_path**: (*default: result*) Directory for perf result..
- **--fp16**: (*default: True*) Enable TensorRT/CUDA FP16 and include the performance of this floating point optimization.
- **--trtexec**: Path of standalone TensorRT executable, for example: trtexec.
- **--track_memory**: Track memory usage of CUDA and TensorRT execution providers
- **--track_memory**: Track memory usage of CUDA and TensorRT execution providers.
- **--ep_list**: Optional argument. List of eps to run against, surround with quotes and separate with spaces.
### Validation Configuration
- **--percent_mismatch**: The allowed percentage of values to be incorrect when comparing given outputs to ORT outputs.
@ -62,84 +79,20 @@ The output of running validation:
Total time for running/profiling all models: 0:20:30.761618
['bert-squad', 'faster-rcnn', 'mask-rcnn', 'ssd', 'tiny-yolov2', 'resnet152v1']
Total models: 6
Fail models: 2
Models FAIL/SUCCESS: 2/4
============================================
========== Failing Models/EPs ==============
============================================
{'faster-rcnn': ['CUDAExecutionProvider_fp16'], 'mask-rcnn': ['CUDAExecutionProvider_fp16']}
========================================
========== TRT detail metrics ==========
========== Models/EPs metrics ==========
========================================
{ 'BERT-Squad': { 'ratio_of_execution_time_in_trt': 0.9980344366695495,
'ratio_of_ops_in_trt': 0.9989451476793249,
'total_execution_time': 12719,
'total_ops': 948,
'total_ops_in_trt': 947,
'total_trt_execution_time': 12694},
'BERT-Squad (FP16)': { 'ratio_of_execution_time_in_trt': 0.9948146725561744,
'ratio_of_ops_in_trt': 0.9989451476793249,
'total_execution_time': 5207,
'total_ops': 948,
'total_ops_in_trt': 947,
'total_trt_execution_time': 5180},
'FasterRCNN-10': { 'ratio_of_execution_time_in_trt': 0.881433685003768,
'ratio_of_ops_in_trt': 0.8637346791636625,
'total_execution_time': 106160,
'total_ops': 2774,
'total_ops_in_trt': 2396,
'total_trt_execution_time': 93573},
'FasterRCNN-10 (FP16)': { 'ratio_of_execution_time_in_trt': 0.8391227836682785,
'total_execution_time': 67623,
'total_trt_execution_time': 56744},
'MaskRCNN-10': { 'ratio_of_execution_time_in_trt': 0.9084868640292711,
'ratio_of_ops_in_trt': 0.8557567917205692,
'total_execution_time': 147039,
'total_ops': 3092,
'total_ops_in_trt': 2646,
'total_trt_execution_time': 133583},
'MaskRCNN-10 (FP16)': { 'ratio_of_execution_time_in_trt': 0.8537288833951381,
'total_execution_time': 87372,
'total_trt_execution_time': 74592},
'Resnet-152-v1': { 'ratio_of_execution_time_in_trt': 1.0,
'ratio_of_ops_in_trt': 1.0,
'total_execution_time': 12330,
'total_ops': 360,
'total_ops_in_trt': 360,
'total_trt_execution_time': 12330},
'Resnet-152-v1 (FP16)': { 'ratio_of_execution_time_in_trt': 1.0,
'ratio_of_ops_in_trt': 1.0,
'total_execution_time': 3201,
'total_ops': 360,
'total_ops_in_trt': 360,
'total_trt_execution_time': 3201},
'SSD': { 'ratio_of_execution_time_in_trt': 0.6751571867232051,
'ratio_of_ops_in_trt': 0.9905660377358491,
'total_execution_time': 102585,
'total_ops': 212,
'total_ops_in_trt': 210,
'total_trt_execution_time': 69261},
'SSD (FP16)': { 'ratio_of_execution_time_in_trt': 0.38334507797420264,
'ratio_of_ops_in_trt': 0.9905660377358491,
'total_execution_time': 32639,
'total_ops': 212,
'total_ops_in_trt': 210,
'total_trt_execution_time': 12512},
'tiny_yolov2': { 'ratio_of_execution_time_in_trt': 1.0,
'ratio_of_ops_in_trt': 1.0,
'total_execution_time': 3003,
'total_ops': 33,
'total_ops_in_trt': 33,
'total_trt_execution_time': 3003},
'tiny_yolov2 (FP16)': { 'ratio_of_execution_time_in_trt': 1.0,
'ratio_of_ops_in_trt': 1.0,
'total_execution_time': 864,
'total_ops': 33,
'total_ops_in_trt': 33,
'total_trt_execution_time': 864}}
'total_trt_execution_time': 12694}}
```
@ -147,40 +100,33 @@ The output of running benchmark:
```
=========================================
=========== CUDA/TRT latency ===========
=========== Models/EPs latency ===========
=========================================
{ 'BERT-Squad': { 'CUDAExecutionProvider': '28.88',
'CUDAExecutionProvider_fp16': '18.08',
'TensorrtExecutionProvider': '15.55',
'TensorrtExecutionProvider_fp16': '5.00',
'Tensorrt_fp16_gain(%)': '72.35 %',
'Tensorrt_gain(%)': '46.16 %'},
'FasterRCNN-10': { 'CUDAExecutionProvider': '161.40',
'TensorrtExecutionProvider': '109.24',
'TensorrtExecutionProvider_fp16': '66.68',
'Tensorrt_gain(%)': '32.32 %'},
'MaskRCNN-10': { 'CUDAExecutionProvider': '221.93',
'TensorrtExecutionProvider': '154.04',
'TensorrtExecutionProvider_fp16': '83.78',
'Tensorrt_gain(%)': '30.59 %'},
'Resnet-152-v1': { 'CUDAExecutionProvider': '22.55',
'CUDAExecutionProvider_fp16': '24.59',
'TensorrtExecutionProvider': '9.82',
'TensorrtExecutionProvider_fp16': '3.22',
'Tensorrt_fp16_gain(%)': '86.91 %',
'Tensorrt_gain(%)': '56.45 %'},
'SSD': { 'CUDAExecutionProvider': '176.23',
'CUDAExecutionProvider_fp16': '82.34',
'TensorrtExecutionProvider': '109.34',
'TensorrtExecutionProvider_fp16': '40.73',
'Tensorrt_fp16_gain(%)': '50.53 %',
'Tensorrt_gain(%)': '37.96 %'},
'tiny_yolov2': { 'CUDAExecutionProvider': '6.99',
'CUDAExecutionProvider_fp16': '5.50',
'TensorrtExecutionProvider': '3.15',
'TensorrtExecutionProvider_fp16': '1.39',
'Tensorrt_fp16_gain(%)': '74.73 %',
'Tensorrt_gain(%)': '54.94 %'}}
{ 'ResNet101-DUC-7': { 'CPUExecutionProvider': { 'average_latency_ms': '10664.04',
'latency_90_percentile': '10923.44'},
'CUDAExecutionProvider': { 'average_latency_ms': '406.66',
'latency_90_percentile': '412.55',
'memory': 13259},
'CUDAExecutionProvider_fp16': { 'average_latency_ms': '129.93',
'latency_90_percentile': '130.80',
'memory': 13003},
'Standalone_TRT': { 'average_latency_ms': '365.334 ',
'latency_90_percentile': '369.046 ',
'memory': 1443},
'Standalone_TRT_fp16': { 'average_latency_ms': '105.71 ',
'latency_90_percentile': '107.01 ',
'memory': 1071},
'TRT_CUDA_fp16_gain(%)': '51.54 %',
'TRT_CUDA_gain(%)': '14.07 %',
'TRT_Standalone_fp16_gain(%)': '40.44 %',
'TRT_Standalone_gain(%)': '4.35 %',
'TensorrtExecutionProvider': { 'average_latency_ms': '349.43',
'latency_90_percentile': '352.53',
'memory': 1941},
'TensorrtExecutionProvider_fp16': { 'average_latency_ms': '62.96',
'latency_90_percentile': '63.96',
'memory': 1257}},
}
```
@ -210,27 +156,28 @@ python comparison_script.py -p "prev" -c "current" -o "output.csv"
### Building ORT Env
build_images.sh: This script should be run before running run_perf_docker.sh to make sure the docker images are up to date.
- **-o, --ort_dockerfile_path**: Path to ORT Docker File.
- **-p, --perf_dockerfile_path**: Path to EP Perf Docker File.
- **-b, --branch**: ORT branch name you are perf testing on.
- **-i, --image**: What the perf docker image will be named.
- **-b, --branch**: ORT branch name you are perf testing on.
ort_build_latest.py: This script should be run before running run_perf_machine.sh or benchmark.py to make sure the latest ORT wheel file is being used.
- **-o, --ort_master_path**: ORT master repo.
- **-t, --tensorrt_home**: TensorRT home directory.
- **-c, --cuda_home**: CUDA home directory.
- **-b, --branch**: (*default: master*) ORT branch name you are perf testing on.
### Running Perf Script
run_perf_docker.sh: Runs the perf script in docker environment.
- **-d, --docker_image**: Name of perf docker image.
- **-o, --option**: Name of which models you want to run {onnx-zoo-models, many-models, partner-models, selected-models}
- **-m, --model_path**: Path to models either json or folder.
- **-o, --option**: Name of which models you want to run {i.e. selected-models}
- **-p, --perf_dir**: Path to perf directory.
- **-m, --model_path**: Model path relative to workspace (/). If option is selected-models, include path to models either json or folder.
run_perf_machine.sh: Runs the perf script in docker environment.
- **-o, --option**: Name of which models you want to run {onnx-zoo-models, many-models, partner-models, selected-models}
- **-m, --model_path**: Path to models either json or folder.
run_perf_machine.sh: Runs the perf script directly.
- **-o, --option**: Name of which models you want to run {i.e. selected-models}
- **-m, --model_path**: Model path relative to workspace (~/). If option is selected-models, include path to models either json or folder.
## Dependencies
- When inferencing model using CUDA float16, this script following script to convert nodes in model graph from float32 to float16. It also modifies the converting script a little bit to better cover more model graph conversion.
https://github.com/microsoft/onnxconverter-common/blob/master/onnxconverter_common/float16.py
- For dynamic input shape models, the script runs symbolic shape inference on the model. https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/python/tools/symbolic_shape_infer.py

View file

@ -54,6 +54,11 @@ LATENCY_FILE = ".latency_map"
METRICS_FILE = ".metrics_map"
MEMORY_FILE = './temp_memory.csv'
def split_and_sort_output(string_list):
string_list = string_list.split("\n")
string_list.sort()
return string_list
def run_trt_standalone(trtexec, model_path, ort_inputs, all_inputs_shape, fp16):
logger.info("running standalone trt")
model_path = "--onnx=" + model_path
@ -75,12 +80,11 @@ def run_trt_standalone(trtexec, model_path, ort_inputs, all_inputs_shape, fp16):
logger.info(shapes_arg)
result = {}
if fp16:
out = get_output([trtexec, model_path, "--fp16", "--percentile=90", "--explicitBatch", shapes_arg])
else:
out = get_output([trtexec, model_path, "--percentile=90", "--explicitBatch", shapes_arg])
command = [trtexec, model_path, "--percentile=90", "--explicitBatch", shapes_arg]
if fp16:
command.extend(["--fp16"])
out = get_output(command)
tmp = out.split("\n")
target_list = []
for t in tmp:
@ -103,12 +107,7 @@ def run_trt_standalone(trtexec, model_path, ort_inputs, all_inputs_shape, fp16):
logger.info(result)
return result
def get_trtexec_path():
trtexec_options = get_output(["find", "/", "-name", "trtexec"])
trtexec_path = re.search(r'.*/workspace/.*/bin/trtexec', trtexec_options).group()
return trtexec_path
def get_latency_result(runtimes, batch_size, mem_mb=None):
def get_latency_result(runtimes, batch_size):
latency_ms = sum(runtimes) / float(len(runtimes)) * 1000.0
latency_variance = numpy.var(runtimes, dtype=numpy.float64) * 1000.0
throughput = batch_size * (1000.0 / latency_ms)
@ -122,8 +121,6 @@ def get_latency_result(runtimes, batch_size, mem_mb=None):
"average_latency_ms": "{:.2f}".format(latency_ms),
"QPS": "{:.2f}".format(throughput),
}
if mem_mb:
result.update({"memory":mem_mb})
return result
@ -178,7 +175,6 @@ def get_trtexec_pid(df, python_pid):
def get_max_memory(trtexec):
df = pd.read_csv(MEMORY_FILE)
pid = df['pid'].iloc[0]
if trtexec:
pid = get_trtexec_pid(df, pid)
@ -187,14 +183,20 @@ def get_max_memory(trtexec):
return max_mem
def start_memory_tracking():
logger.info("starting memory tracking process")
p = subprocess.Popen(["nvidia-smi", "--query-compute-apps=pid,used_memory", "--format=csv", "-l", "1", "-f", MEMORY_FILE])
return p
def end_memory_tracking(p, trtexec):
def end_memory_tracking(p, trtexec, success):
logger.info("terminating memory tracking process")
p.terminate()
p.wait()
mem_usage = get_max_memory(trtexec)
os.remove(MEMORY_FILE)
p.kill()
mem_usage = None
if success:
mem_usage = get_max_memory(trtexec)
if os.path.exists(MEMORY_FILE):
os.remove(MEMORY_FILE)
return mem_usage
def inference_ort(args, name, session, ep, ort_inputs, result_template, repeat_times, batch_size):
@ -214,30 +216,20 @@ def inference_ort(args, name, session, ep, ort_inputs, result_template, repeat_t
logger.info(sess_outputs)
try:
if args.track_memory and track_ep_memory(ep):
p = start_memory_tracking()
runtime = timeit.repeat(lambda: session.run(sess_outputs, sess_inputs), number=1, repeat=repeat_times)
mem_usage = end_memory_tracking(p, False)
else:
runtime = timeit.repeat(lambda: session.run(sess_outputs, sess_inputs), number=1, repeat=repeat_times)
runtimes += runtime
runtime = timeit.repeat(lambda: session.run(sess_outputs, sess_inputs), number=1, repeat=repeat_times)
runtimes += runtime[1:] # remove warmup
except Exception as e:
logger.error(e)
return None
logger.info(runtimes)
runtimes[:] = runtimes[1:]
logger.info(runtimes)
result = {}
result.update(result_template)
result.update({"io_binding": False})
latency_result = get_latency_result(runtimes, batch_size, mem_usage)
latency_result = get_latency_result(runtimes, batch_size)
result.update(latency_result)
logger.info(result)
return result
def inference_ort_and_get_prediction(name, session, ort_inputs):
@ -289,11 +281,8 @@ def get_acl_version():
#######################################################################################################################################
def load_onnx_model_zoo_test_data(path, all_inputs_shape, data_type="fp32"):
logger.info("Parsing test data in {} ...".format(path))
p1 = subprocess.Popen(["find", path, "-name", "test_data*", "-type", "d"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["sort"], stdin=p1.stdout, stdout=subprocess.PIPE)
stdout, sterr = p2.communicate()
stdout = stdout.decode("ascii").strip()
test_data_set_dir = stdout.split("\n")
output = get_output(["find", path, "-name", "test_data*", "-type", "d"])
test_data_set_dir = split_and_sort_output(output)
logger.info(test_data_set_dir)
inputs = []
@ -310,11 +299,8 @@ def load_onnx_model_zoo_test_data(path, all_inputs_shape, data_type="fp32"):
os.chdir(test_data_dir)
# load inputs
p1 = subprocess.Popen(["find", ".", "-name", "input*"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["sort"], stdin=p1.stdout, stdout=subprocess.PIPE)
stdout, sterr = p2.communicate()
stdout = stdout.decode("ascii").strip()
input_data = stdout.split("\n")
output = get_output(["find", ".", "-name", "input*"])
input_data = split_and_sort_output(output)
logger.info(input_data)
input_data_pb = []
@ -322,14 +308,10 @@ def load_onnx_model_zoo_test_data(path, all_inputs_shape, data_type="fp32"):
tensor = onnx.TensorProto()
with open(data, 'rb') as f:
tensor.ParseFromString(f.read())
tensor_to_array = numpy_helper.to_array(tensor)
if data_type == "fp16" and tensor_to_array.dtype == np.dtype(np.float32):
tensor_to_array = tensor_to_array.astype(np.float16)
input_data_pb.append(tensor_to_array)
# print(np.array(input_data_pb[-1]).shape)
if not shape_flag:
all_inputs_shape.append(input_data_pb[-1].shape)
logger.info(all_inputs_shape[-1])
@ -337,14 +319,11 @@ def load_onnx_model_zoo_test_data(path, all_inputs_shape, data_type="fp32"):
logger.info('Loaded {} inputs successfully.'.format(len(inputs)))
# load outputs
p1 = subprocess.Popen(["find", ".", "-name", "output*"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["sort"], stdin=p1.stdout, stdout=subprocess.PIPE)
stdout, sterr = p2.communicate()
stdout = stdout.decode("ascii").strip()
output_data = stdout.split("\n")
logger.info(output_data)
output = get_output(["find", ".", "-name", "output*"])
output_data = split_and_sort_output(output)
if len(output_data) > 0 and output_data[0] != '':
logger.info(output_data)
output_data_pb = []
for data in output_data:
tensor = onnx.TensorProto()
@ -469,7 +448,7 @@ def remove_profiling_files(path):
for f in files:
if "custom_test_data" in f:
continue
subprocess.Popen(["sudo","rm","-rf", f], stdout=subprocess.PIPE)
subprocess.Popen(["rm","-rf", f], stdout=subprocess.PIPE)
def update_fail_report(fail_results, model, ep, e_type, e):
@ -654,9 +633,11 @@ def get_cuda_version():
version = re.search(r'CUDA Version: \d\d\.\d', nvidia_strings).group(0)
return version
def get_trt_version():
nvidia_strings = get_output(["dpkg", "-l"])
version = re.search(r'nvinfer.*\d\.\d\.\d\-\d', nvidia_strings).group(0)
def get_trt_version(workspace):
libnvinfer = get_output(["find", workspace, "-name", "libnvinfer.so.*"])
nvinfer = re.search(r'.*libnvinfer.so.*', libnvinfer).group(0)
trt_strings = get_output(["nm", "-D", nvinfer])
version = re.search(r'tensorrt_version.*', trt_strings).group(0)
return version
def get_linux_distro():
@ -694,10 +675,10 @@ def get_gpu_info():
infos = re.findall('NVIDIA.*', info)
return infos
def get_system_info():
def get_system_info(workspace):
info = {}
info["cuda"] = get_cuda_version()
info["trt"] = get_trt_version()
info["trt"] = get_trt_version(workspace)
info["linux_distro"] = get_linux_distro()
info["cpu_info"] = get_cpu_info()
info["gpu_info"] = get_gpu_info()
@ -706,10 +687,8 @@ def get_system_info():
return info
def find_model_path(path):
p1 = subprocess.Popen(["find", path, "-name", "*.onnx"], stdout=subprocess.PIPE)
stdout, sterr = p1.communicate()
stdout = stdout.decode("ascii").strip()
model_path = stdout.split("\n")
output = get_output(["find", "-L", path, "-name", "*.onnx"])
model_path = split_and_sort_output(output)
logger.info(model_path)
if model_path == ['']:
@ -729,23 +708,16 @@ def find_model_path(path):
return target_model_path[0]
def find_model_directory(path):
p1 = subprocess.Popen(["find", path, "-maxdepth", "1", "-mindepth", "1", "-name", "*", "-type", "d"], stdout=subprocess.PIPE)
stdout, sterr = p1.communicate()
stdout = stdout.decode("ascii").strip()
model_dir = stdout.split("\n")
# print(model_dir)
output = get_output(["find", "-L", path, "-maxdepth", "1", "-mindepth", "1", "-name", "*", "-type", "d"])
model_dir = split_and_sort_output(output)
if model_dir == ['']:
return None
return model_dir
def find_test_data_directory(path):
p1 = subprocess.Popen(["find", path, "-maxdepth", "1", "-name", "test_data*", "-type", "d"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["sort"], stdin=p1.stdout, stdout=subprocess.PIPE)
stdout, sterr = p2.communicate()
stdout = stdout.decode("ascii").strip()
test_data_dir = stdout.split("\n")
output = get_output(["find", "-L", path, "-maxdepth", "1", "-name", "test_data*", "-type", "d"])
test_data_dir = split_and_sort_output(output)
logger.info(test_data_dir)
if test_data_dir == ['']:
@ -783,7 +755,7 @@ def parse_models_info_from_directory(path, models):
def parse_models_info_from_file(root_dir, path, models):
# default working directory
root_working_directory = root_dir
root_working_directory = root_dir + 'perf/'
with open(path) as f:
data = json.load(f)
@ -806,7 +778,7 @@ def parse_models_info_from_file(root_dir, path, models):
if os.path.isabs(row['working_directory']):
model['working_directory'] = row['working_directory']
else:
model['working_directory'] = os.path.join(root_working_directory + row['working_directory'])
model['working_directory'] = os.path.join(root_working_directory, row['working_directory'])
else:
logger.error('Model path must be provided in models_info.json')
raise
@ -831,15 +803,16 @@ def parse_models_info_from_file(root_dir, path, models):
def convert_model_from_float_to_float16(model_path):
# from onnxmltools.utils.float16_converter import convert_float_to_float16
from onnxmltools.utils import load_model, save_model
from float16 import convert_float_to_float16
onnx_model = load_model(model_path)
new_onnx_model = convert_float_to_float16(onnx_model)
save_model(new_onnx_model, 'new_fp16_model_by_trt_perf.onnx')
new_model_path = os.path.join(os.getcwd(), "new_fp16_model_by_trt_perf.onnx")
if not os.path.exists(new_model_path):
onnx_model = load_model(model_path)
new_onnx_model = convert_float_to_float16(onnx_model)
save_model(new_onnx_model, 'new_fp16_model_by_trt_perf.onnx')
return os.path.join(os.getcwd(), "new_fp16_model_by_trt_perf.onnx")
return new_model_path
def get_test_data(fp16, test_data_dir, all_inputs_shape):
inputs = []
@ -854,25 +827,25 @@ def get_test_data(fp16, test_data_dir, all_inputs_shape):
return inputs, ref_outputs
def create_session(model_path, providers, session_options):
logger.info(model_path)
try:
session = onnxruntime.InferenceSession(model_path, providers=providers, sess_options=session_options)
return session
except:
logger.info("Use symbolic_shape_infer.py")
except Exception as e:
if "shape inference" in str(e):
logger.info("Using model from symbolic_shape_infer.py")
new_model_path = model_path[:].replace(".onnx", "_new_by_trt_perf.onnx")
exec = os.environ["SYMBOLIC_SHAPE_INFER"]
new_model_path = model_path[:].replace(".onnx", "_new_by_trt_perf.onnx")
exec = os.environ["SYMBOLIC_SHAPE_INFER"]
logger.info(exec)
if not os.path.exists(new_model_path):
subprocess.run("python3 " + exec +" --input " + model_path + " --output " + new_model_path + " --auto_merge", shell=True, check=True)
session = onnxruntime.InferenceSession(new_model_path, providers=providers, sess_options=session_options)
return session
if not os.path.exists(new_model_path):
p = subprocess.run("python3 " + exec + " --input " + model_path + " --output " + new_model_path + " --auto_merge", shell=True, check=True, )
logger.info(p)
session = onnxruntime.InferenceSession(new_model_path, providers=providers, sess_options=session_options)
return session
else:
raise Exception(e)
def run_onnxruntime(args, models):
@ -923,23 +896,25 @@ def run_onnxruntime(args, models):
# iterate ep
#######################
for ep in ep_list:
if skip_ep(name, ep, model_to_fail_ep):
continue
ep_ = ep_to_provider_list[ep][0]
if (ep_ not in onnxruntime.get_available_providers()):
logger.error("No {} support".format(ep_))
continue
if standalone_trt not in ep:
ep_ = ep_to_provider_list[ep][0]
if (ep_ not in onnxruntime.get_available_providers()):
logger.error("No {} support".format(ep_))
continue
model_path = model_info["model_path"]
test_data_dir = model_info["test_data_path"]
if ep == cuda_fp16:
logger.info("[Initialize] model = {}, ep = {} ,FP16 = True ...".format(name, ep))
fp16 = True
os.environ["ORT_TENSORRT_FP16_ENABLE"] = "1"
fp16 = False
os.environ["ORT_TENSORRT_FP16_ENABLE"] = "1" if "fp16" in ep else "0"
logger.info("[Initialize] model = {}, ep = {} ...".format(name, ep))
# use float16.py for cuda fp16 only
if "cuda_fp16" in ep:
# handle model
if "model_path_fp16" in model_info:
model_path = model_info["model_path_fp16"]
@ -947,7 +922,7 @@ def run_onnxruntime(args, models):
else:
try:
model_path = convert_model_from_float_to_float16(model_path)
fp16 = True
except Exception as e:
logger.error(e)
update_fail_model_map(model_to_fail_ep, name, ep, 'script error', e)
@ -956,23 +931,9 @@ def run_onnxruntime(args, models):
# handle test data
if "test_data_path_fp16" in model_info:
test_data_dir = model_info["test_data_path_fp16"]
inputs, ref_outputs = get_test_data(False, test_data_dir, all_inputs_shape)
else:
inputs, ref_outputs = get_test_data(True, test_data_dir, all_inputs_shape)
fp16 = False
elif ep == trt_fp16:
logger.info("[Initialize] model = {}, ep = {} ,FP16 = True ...".format(name, ep))
fp16 = True
os.environ["ORT_TENSORRT_FP16_ENABLE"] = "1"
inputs, ref_outputs = get_test_data(False, test_data_dir, all_inputs_shape)
else:
logger.info("[Initialize] model = {}, ep = {} ,FP16 = False ...".format(name, ep))
fp16 = False
os.environ["ORT_TENSORRT_FP16_ENABLE"] = "0"
inputs, ref_outputs = get_test_data(False, test_data_dir, all_inputs_shape)
inputs, ref_outputs = get_test_data(fp16, test_data_dir, all_inputs_shape)
# generate random input data
if args.input_data == "random":
@ -984,82 +945,94 @@ def run_onnxruntime(args, models):
if args.running_mode == 'benchmark':
logger.info("\n----------------------------- benchmark -------------------------------------")
# resolve providers to create session
if standalone_trt in ep:
providers = ep_to_provider_list[trt]
else:
providers = ep_to_provider_list[ep]
options = onnxruntime.SessionOptions()
options.graph_optimization_level = onnxruntime.GraphOptimizationLevel.ORT_ENABLE_ALL
# create onnxruntime inference session
try:
sess = create_session(model_path, ep_to_provider_list[ep], options)
sess = create_session(model_path, providers, options)
except Exception as e:
logger.error(e)
update_fail_model_map(model_to_fail_ep, name, ep, 'runtime error', e)
continue
logger.info("start to inference {} with {} ...".format(name, ep))
logger.info(sess.get_providers())
if sess:
logger.info("Model inputs nodes:")
for input_meta in sess.get_inputs():
logger.info(input_meta)
logger.info("Model outputs nodes:")
for output_meta in sess.get_outputs():
logger.info(output_meta)
batch_size = 1
result_template = {
"engine": "onnxruntime",
"version": onnxruntime.__version__,
"device": ep,
"fp16": fp16,
"io_binding": False,
"model_name": name,
"inputs": len(sess.get_inputs()),
"batch_size": batch_size,
"sequence_length": 1,
"datetime": str(datetime.now()),}
if trt in ep and args.trtexec:
# get standalone TensorRT perf
# memory tracking variables
p = None # keep track of process to kill upon error
mem_usage = None
# get standalone TensorRT perf
if standalone_trt in ep and args.trtexec:
trtexec = True
try:
ep = standalone_trt_fp16 if fp16 else standalone_trt
if args.track_memory:
p = start_memory_tracking()
result = run_trt_standalone(args.trtexec, model_path, sess.get_inputs(), all_inputs_shape, fp16)
mem_usage = end_memory_tracking(p, True)
if result and mem_usage:
result["memory"] = mem_usage
mem_usage = end_memory_tracking(p, trtexec, True)
else:
result = run_trt_standalone(args.trtexec, model_path, sess.get_inputs(), all_inputs_shape, fp16)
except Exception as e:
logger.error(e)
if args.track_memory:
end_memory_tracking(p, trtexec, False)
update_fail_model_map(model_to_fail_ep, name, ep, 'runtime error', e)
continue
else:
result = inference_ort(args, name, sess, ep, inputs, result_template, args.test_times, batch_size)
if result:
# inference with onnxruntime ep
else:
logger.info("start to inference {} with {} ...".format(name, ep))
logger.info(sess.get_providers())
if sess:
logger.info("Model inputs nodes:")
for input_meta in sess.get_inputs():
logger.info(input_meta)
logger.info("Model outputs nodes:")
for output_meta in sess.get_outputs():
logger.info(output_meta)
batch_size = 1
result_template = {
"engine": "onnxruntime",
"version": onnxruntime.__version__,
"device": ep,
"fp16": fp16,
"io_binding": False,
"model_name": name,
"inputs": len(sess.get_inputs()),
"batch_size": batch_size,
"sequence_length": 1,
"datetime": str(datetime.now()),}
if args.track_memory and track_ep_memory(ep):
trtexec = False
p = start_memory_tracking()
result = inference_ort(args, name, sess, ep, inputs, result_template, args.test_times, batch_size)
success = True if result else False
mem_usage = end_memory_tracking(p, trtexec, success)
else:
result = inference_ort(args, name, sess, ep, inputs, result_template, args.test_times, batch_size)
if result:
latency_result[ep] = {}
latency_result[ep]["average_latency_ms"] = result["average_latency_ms"]
latency_result[ep]["latency_90_percentile"] = result["latency_90_percentile"]
if "memory" in result:
mem_usage = result.pop("memory")
if mem_usage:
latency_result[ep]["memory"] = mem_usage
if not args.trtexec: # skip standalone
success_results.append(result)
model_to_latency[name] = copy.deepcopy(latency_result)
logger.info("---------------------------- benchmark [end] ----------------------------------\n")
elif args.running_mode == 'validate':
logger.info("\n----------------------------- validate -------------------------------------")
@ -1072,7 +1045,6 @@ def run_onnxruntime(args, models):
# create onnxruntime inference session
try:
sess = create_session(model_path, ep_to_provider_list[ep], options)
except Exception as e:
logger.error(e)
update_fail_model_map(model_to_fail_ep, name, ep, 'runtime error', e)
@ -1179,8 +1151,6 @@ def output_details(results, csv_filename):
for result in results:
csv_writer.writerow(result)
logger.info(f"Detail results are saved to csv file: {csv_filename}")
def output_fail(model_to_fail_ep, csv_filename):
with open(csv_filename, mode="w", newline='') as csv_file:
@ -1197,8 +1167,6 @@ def output_fail(model_to_fail_ep, csv_filename):
result["error type"] = ep_info["error_type"]
result["error message"] = ep_info["error_message"]
csv_writer.writerow(result)
logger.info(f"Failing results are saved to csv file: {csv_filename}")
def read_success_from_file(success_file):
success_results = []
@ -1549,8 +1517,6 @@ def parse_arguments():
parser.add_argument("-c", "--comparison", required=False, default="cuda_trt", choices=["cuda_trt", "acl"], help="EPs to compare: CPU vs. CUDA vs. TRT or CPU vs. ACL")
parser.add_argument("-d", "--working_dir", required=False, default="./", help="Perf folder path")
parser.add_argument("-m", "--model_source", required=False, default="model_list.json", help="Model source: (1) model list file (2) model directory.")
parser.add_argument("-r", "--running_mode", required=False, default="benchmark", choices=["validate", "benchmark"], help="Testing mode.")
@ -1559,9 +1525,13 @@ def parse_arguments():
parser.add_argument("-o", "--perf_result_path", required=False, default="result", help="Directory for perf result.")
parser.add_argument("-w", "--workspace", required=False, default="/", help="Workspace to find tensorrt and perf script (with models if parsing with model file)")
parser.add_argument("--track_memory", required=False, default=True, help="Track CUDA and TRT Memory Usage")
parser.add_argument("--ep", required=False, default=None, help="Specify ORT Execution Provider.")
parser.add_argument("--ep_list", nargs="+", required=False, default=None, help="Specify ORT Execution Providers list.")
parser.add_argument("--fp16", required=False, default=True, action="store_true", help="Inlcude Float16 into benchmarking.")
@ -1599,7 +1569,7 @@ def setup_logger(verbose):
def parse_models_helper(args, models):
if ".json" in args.model_source:
logger.info("Parsing model information from file ...")
parse_models_info_from_file(args.working_dir, args.model_source, models)
parse_models_info_from_file(args.workspace, args.model_source, models)
else:
logger.info("Parsing model information from directory ...")
parse_models_info_from_directory(args.model_source, models)
@ -1608,16 +1578,13 @@ def main():
args = parse_arguments()
setup_logger(False)
pp = pprint.PrettyPrinter(indent=4)
logger.info("\n\nStart perf run ...\n")
models = {}
parse_models_helper(args, models)
if not os.path.exists("symbolic_shape_infer.py"):
p1 = subprocess.Popen(["sudo", "wget", "https://raw.githubusercontent.com/microsoft/onnxruntime/master/onnxruntime/python/tools/symbolic_shape_infer.py"])
p1.wait()
os.environ["SYMBOLIC_SHAPE_INFER"] = os.path.join(os.getcwd(), "symbolic_shape_infer.py")
os.environ["SYMBOLIC_SHAPE_INFER"] = os.path.join(os.getcwd(), "../../symbolic_shape_infer.py")
perf_start_time = datetime.now()
success_results, model_to_latency, model_to_fail_ep, model_to_metrics = run_onnxruntime(args, models)
@ -1659,7 +1626,7 @@ def main():
logger.info("=========== Models/EPs latency ===========")
logger.info("==========================================")
add_improvement_information(model_to_latency)
pp.pprint(model_to_latency)
pretty_print(pp, model_to_latency)
write_map_to_file(model_to_latency, LATENCY_FILE)
if args.write_test_result:
csv_filename = args.benchmark_latency_csv if args.benchmark_latency_csv else f"benchmark_latency_{time_stamp}.csv"
@ -1675,7 +1642,7 @@ def main():
logger.info("\n=========================================")
logger.info("========== Models/EPs metrics ==========")
logger.info("=========================================")
pp.pprint(model_to_metrics)
pretty_print(pp, model_to_metrics)
write_map_to_file(model_to_metrics, METRICS_FILE)
if args.write_test_result:
@ -1683,16 +1650,5 @@ def main():
csv_filename = os.path.join(path, csv_filename)
output_metrics(model_to_metrics, csv_filename)
if False:
logger.info("\n===========================================")
logger.info("=========== System information ===========")
logger.info("===========================================")
info = get_system_info()
pp.pprint(info)
csv_filename = args.benchmark_fail_csv if args.benchmark_fail_csv else f"system_info_csv{time_stamp}.csv"
csv_filename = os.path.join(path, csv_filename)
output_system_info(info, csv_filename)
if __name__ == "__main__":
main()

View file

@ -21,11 +21,26 @@ def get_ep_list(comparison):
ep_list = [cpu, cuda, trt, standalone_trt, cuda_fp16, trt_fp16, standalone_trt_fp16]
return ep_list
def resolve_trtexec_path(workspace):
trtexec_options = get_output(["find", workspace, "-name", "trtexec"])
trtexec_path = re.search(r'.*/bin/trtexec', trtexec_options).group(0)
logger.info("using trtexec {}".format(trtexec_path))
return trtexec_path
def main():
args = parse_arguments()
setup_logger(False)
pp = pprint.PrettyPrinter(indent=4)
# create ep list to iterate through
if args.ep_list:
ep_list = args.ep_list
else:
ep_list = get_ep_list(args.comparison)
if standalone_trt in ep_list or standalone_trt_fp16 in ep_list:
trtexec = resolve_trtexec_path(args.workspace)
models = {}
parse_models_helper(args, models)
@ -47,11 +62,6 @@ def main():
model_list_file = os.path.join(os.getcwd(), model +'.json')
write_model_info_to_file([model_info], model_list_file)
if args.ep:
ep_list = [args.ep]
else:
ep_list = get_ep_list(args.comparison)
for ep in ep_list:
command = ["python3",
@ -59,35 +69,32 @@ def main():
"-r", args.running_mode,
"-m", model_list_file,
"-o", args.perf_result_path,
"--ep", ep,
"--write_test_result", "false"]
if "Standalone" in ep:
if args.running_mode == "validate":
continue
else:
trtexec_path = get_trtexec_path()
command.extend(["--trtexec", trtexec_path])
ep = trt_fp16 if "fp16" in ep else trt
command.extend(["--trtexec", trtexec])
command.extend(["--ep", ep])
if args.running_mode == "validate":
command.extend(["--benchmark_fail_csv", benchmark_fail_csv,
"--benchmark_metrics_csv", benchmark_metrics_csv])
command.extend(["--benchmark_metrics_csv", benchmark_metrics_csv])
elif args.running_mode == "benchmark":
command.extend(["-t", str(args.test_times),
"-o", args.perf_result_path,
"--write_test_result", "false",
"--benchmark_fail_csv", benchmark_fail_csv,
"--benchmark_latency_csv", benchmark_latency_csv,
"--benchmark_success_csv", benchmark_success_csv])
p = subprocess.run(command)
logger.info(p)
if p.returncode != 0:
error_type = "runtime error"
error_message = "perf script exited with returncode = " + str(p.returncode)
error_message = "Benchmark script exited with returncode = " + str(p.returncode)
logger.error(error_message)
update_fail_model_map(model_to_fail_ep, model, ep, error_type, error_message)
write_map_to_file(model_to_fail_ep, FAIL_MODEL_FILE)
@ -101,16 +108,6 @@ def main():
Path(path).mkdir(parents=True, exist_ok=True)
if args.running_mode == "validate":
logger.info("\n=========================================================")
logger.info("========== Failing Models/EPs (accumulated) ==============")
logger.info("==========================================================")
if os.path.exists(FAIL_MODEL_FILE) or len(model_to_fail_ep) > 1:
model_to_fail_ep = read_map_from_file(FAIL_MODEL_FILE)
output_fail(model_to_fail_ep, os.path.join(path, benchmark_fail_csv))
logger.info("\nSaved model fail results to {}".format(benchmark_fail_csv))
logger.info(model_to_fail_ep)
logger.info("\n=========================================")
logger.info("=========== Models/EPs metrics ==========")
logger.info("=========================================")
@ -121,6 +118,16 @@ def main():
logger.info("\nSaved model metrics results to {}".format(benchmark_metrics_csv))
elif args.running_mode == "benchmark":
logger.info("\n=========================================================")
logger.info("========== Failing Models/EPs (accumulated) ==============")
logger.info("==========================================================")
if os.path.exists(FAIL_MODEL_FILE) or len(model_to_fail_ep) > 1:
model_to_fail_ep = read_map_from_file(FAIL_MODEL_FILE)
output_fail(model_to_fail_ep, os.path.join(path, benchmark_fail_csv))
logger.info(model_to_fail_ep)
logger.info("\nSaved model failing results to {}".format(benchmark_fail_csv))
logger.info("\n=======================================================")
logger.info("=========== Models/EPs Status (accumulated) ===========")
logger.info("=======================================================")
@ -156,8 +163,9 @@ def main():
logger.info("\n===========================================")
logger.info("=========== System information ===========")
logger.info("===========================================")
info = get_system_info()
info = get_system_info(args.workspace)
pretty_print(pp, info)
logger.info("\n")
if __name__ == "__main__":
main()

View file

@ -15,7 +15,7 @@ RUN apt-get update &&\
RUN unattended-upgrade
WORKDIR /code
ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.14.3-Linux-x86_64/bin:/opt/miniconda/bin:${PATH}
ENV PATH /usr/local/nvidia/bin:/usr/local/cuda/bin:/code/cmake-3.18.3-Linux-x86_64/bin:/opt/miniconda/bin:${PATH}
ENV LD_LIBRARY_PATH /opt/miniconda/lib:$LD_LIBRARY_PATH
# Prepare onnxruntime repository & build onnxruntime with TensorRT
@ -28,4 +28,4 @@ RUN git clone --single-branch --branch ${ONNXRUNTIME_BRANCH} --recursive ${ONNXR
/bin/sh ./build.sh --parallel --cuda_home /usr/local/cuda --cudnn_home /usr/lib/x86_64-linux-gnu/ --use_tensorrt --tensorrt_home /workspace/tensorrt --config Release --build_wheel --update --build --cmake_extra_defines ONNXRUNTIME_VERSION=$(cat ./VERSION_NUMBER) &&\
pip install /code/onnxruntime/build/Linux/Release/dist/*.whl &&\
cd .. &&\
rm -rf onnxruntime cmake-3.14.3-Linux-x86_64
rm -rf onnxruntime cmake-3.18.3-Linux-x86_64

View file

@ -13,9 +13,9 @@ apt-get update && apt-get install -y --no-install-recommends \
protobuf-compiler \
pciutils
pip install pandas coloredlogs numpy flake8 onnx Cython onnxmltools sympy packaging psutil
pip install pandas coloredlogs numpy flake8 onnx Cython onnxmltools sympy packaging psutil mysql-connector-python SQLAlchemy
# Dependencies: cmake
wget --quiet https://github.com/Kitware/CMake/releases/download/v3.14.3/cmake-3.14.3-Linux-x86_64.tar.gz
tar zxf cmake-3.14.3-Linux-x86_64.tar.gz
rm -rf cmake-3.14.3-Linux-x86_64.tar.gz
wget --quiet https://github.com/Kitware/CMake/releases/download/v3.18.3/cmake-3.18.3-Linux-x86_64.tar.gz
tar zxf cmake-3.18.3-Linux-x86_64.tar.gz
rm -rf cmake-3.18.3-Linux-x86_64.tar.gz

View file

@ -2,7 +2,6 @@ import os
import subprocess
import argparse
import tarfile
from perf_utils import get_latest_commit_hash
def parse_arguments():
parser = argparse.ArgumentParser()
@ -10,7 +9,7 @@ def parse_arguments():
parser.add_argument("-o", "--ort_master_path", required=True, help="ORT master repo")
parser.add_argument("-t", "--tensorrt_home", required=True, help="TensorRT home directory")
parser.add_argument("-c", "--cuda_home", required=True, help="CUDA home directory")
parser.add_argument("-v", "--commit_hash", required = False, help="Github commit to test perf off of")
parser.add_argument("-b", "--branch", required=False, default="master", help="Github branch to test perf off of")
parser.add_argument("-s", "--save", required=False, help="Directory to archive wheel file")
parser.add_argument("-a", "--use_archived", required=False, help="Archived wheel file")
args = parser.parse_args()
@ -19,30 +18,27 @@ def parse_arguments():
def archive_wheel_file(save_path, ort_wheel_file):
if not os.path.exists(save_path):
os.mkdir(save_path)
p1 = subprocess.Popen(["cp", ort_wheel_file, save_path])
p1.wait()
subprocess.run(["cp", ort_wheel_file, save_path], check=True)
def install_new_ort_wheel(ort_master_path):
ort_wheel_path = os.path.join(ort_master_path, "build", "Linux", "Release", "dist")
p1 = subprocess.Popen(["find", ort_wheel_path, "-name", "*.whl"], stdout=subprocess.PIPE)
stdout, sterr = p1.communicate()
stdout = stdout.decode("utf-8").strip()
p1 = subprocess.run(["find", ort_wheel_path, "-name", "*.whl"], stdout=subprocess.PIPE, check=True)
stdout = p1.stdout.decode("utf-8").strip()
ort_wheel = stdout.split("\n")[0]
p1 = subprocess.Popen(["pip3", "install", "-I", ort_wheel])
p1.wait()
subprocess.run(["python3", "-m", "pip", "install", "--force-reinstall", ort_wheel], check=True)
return ort_wheel
def main():
args = parse_arguments()
cmake_tar = "cmake-3.17.4-Linux-x86_64.tar.gz"
cmake_tar = "cmake-3.18.4-Linux-x86_64.tar.gz"
if not os.path.exists(cmake_tar):
p = subprocess.run(["wget", "-c", "https://cmake.org/files/v3.17/" + cmake_tar], check=True)
p = subprocess.run(["wget", "-c", "https://cmake.org/files/v3.18/" + cmake_tar], check=True)
tar = tarfile.open(cmake_tar)
tar.extractall()
tar.close()
os.environ["PATH"] = os.path.join(os.path.abspath("cmake-3.17.4-Linux-x86_64"), "bin") + ":" + os.environ["PATH"]
os.environ["PATH"] = os.path.join(os.path.abspath("cmake-3.18.4-Linux-x86_64"), "bin") + ":" + os.environ["PATH"]
os.environ["CUDACXX"] = os.path.join(args.cuda_home, "bin", "nvcc")
ort_master_path = args.ort_master_path
@ -51,26 +47,18 @@ def main():
if args.use_archived:
ort_wheel_file = args.use_archived
p1 = subprocess.Popen(["pip3", "install", "-I", ort_wheel_file])
p1.wait()
subprocess.run(["python3", "-m", "pip", "install", "--force-reinstall", ort_wheel_file], check=True)
else:
if args.commit_hash:
commit = args.commit_hash
p1 = subprocess.Popen(["git", "checkout", commit])
else:
commit = get_latest_commit_hash()
p1 = subprocess.Popen(["git", "pull", "origin", "master"])
p1.wait()
p1 = subprocess.Popen(["./build.sh", "--config", "Release", "--use_tensorrt", "--tensorrt_home", args.tensorrt_home, "--cuda_home", args.cuda_home, "--cudnn", "/usr/lib/x86_64-linux-gnu", "--build_wheel", "--skip_tests", "--parallel"])
p1.wait()
subprocess.run(["git", "fetch"], check=True)
subprocess.run(["git", "checkout", args.branch], check=True)
subprocess.run(["git", "pull", "origin", args.branch], check=True)
subprocess.run(["./build.sh", "--config", "Release", "--use_tensorrt", "--tensorrt_home", args.tensorrt_home, "--cuda_home", args.cuda_home, "--cudnn", "/usr/lib/x86_64-linux-gnu", "--build_wheel", "--skip_tests", "--parallel"], check=True)
ort_wheel_file = install_new_ort_wheel(ort_master_path)
if args.save:
save_path = os.path.join(args.save, commit)
archive_wheel_file(save_path, ort_wheel_file)
archive_wheel_file(args.save, ort_wheel_file)
os.chdir(pwd)

View file

@ -1,14 +1,30 @@
#!/bin/bash
while getopts d:o:m: parameter
while getopts d:o:m:w:e: parameter
do case "${parameter}"
in
in
d) PERF_DIR=${OPTARG};;
o) OPTION=${OPTARG};;
m) MODEL_PATH=${OPTARG};;
w) WORKSPACE=${OPTARG};;
e) EP_LIST=${OPTARG};;
esac
done
# add ep list
RUN_EPS=""
if [ ! -z "$EP_LIST" ]
then
RUN_EPS="--ep_list $EP_LIST"
fi
# change dir if docker
if [ ! -z $PERF_DIR ]
then
echo 'changing to '$PERF_DIR
cd $PERF_DIR
fi
# metadata
FAIL_MODEL_FILE=".fail_model_map"
LATENCY_FILE=".latency_map"
@ -16,8 +32,6 @@ METRICS_FILE=".metrics_map"
PROFILE="*onnxruntime_profile*"
# files to download info
SYMBOLIC_SHAPE_INFER="symbolic_shape_infer.py"
SYMBOLIC_SHAPE_INFER_LINK="https://raw.githubusercontent.com/microsoft/onnxruntime/master/onnxruntime/python/tools/symbolic_shape_infer.py"
FLOAT_16="float16.py"
FLOAT_16_LINK="https://raw.githubusercontent.com/microsoft/onnxconverter-common/master/onnxconverter_common/float16.py"
@ -25,23 +39,20 @@ cleanup_files() {
rm -f $FAIL_MODEL_FILE
rm -f $LATENCY_FILE
rm -f $METRICS_FILE
rm -f $SYMBOLIC_SHAPE_INFER
rm -f $FLOAT_16
rm -rf result/$OPTION
find -name $PROFILE -delete
}
download_files() {
wget --no-check-certificate -c $SYMBOLIC_SHAPE_INFER_LINK
wget --no-check-certificate -c $FLOAT_16_LINK
}
setup() {
cd $PERF_DIR
cleanup_files
download_files
}
setup
python3 benchmark_wrapper.py -r validate -m $MODEL_PATH -o result/$OPTION
python3 benchmark_wrapper.py -r benchmark -i random -t 10 -m $MODEL_PATH -o result/$OPTION
python3 benchmark_wrapper.py -r validate -m $MODEL_PATH -o result/$OPTION -w $WORKSPACE $RUN_EPS
python3 benchmark_wrapper.py -r benchmark -t 10 -m $MODEL_PATH -o result/$OPTION -w $WORKSPACE $RUN_EPS

View file

@ -24,10 +24,6 @@ def pretty_print(pp, json_object):
pp.pprint(json_object)
sys.stdout.flush()
def get_latest_commit_hash():
commit = get_output(["git", "rev-parse", "--short", "HEAD"])
return commit
def parse_single_file(f):
try:

View file

@ -42,7 +42,7 @@ def insert_latency(commit_hash, report_url, latency):
# delete old records
delete_query = ('DELETE FROM onnxruntime.ep_latency_over_time '
'WHERE UploadTime < DATE_SUB(Now(), INTERVAL 30 DAY);'
'WHERE UploadTime < DATE_SUB(Now(), INTERVAL 100 DAY);'
)
cursor.execute(delete_query)
@ -144,9 +144,9 @@ def main():
cert = get_database_cert()
ssl_args = {'ssl_ca': cert}
connection_string = sql_connector + \
user + \
user + ':' + \
password + \
host + \
'@' + host + '/' + \
database
engine = create_engine(connection_string, connect_args=ssl_args)

View file

@ -1,46 +1,21 @@
#!/bin/bash
# Parse Arguments
while getopts d:o:m:p: parameter
while getopts d:o:m:p:e: parameter
do case "${parameter}"
in
d) DOCKER_IMAGE=${OPTARG};;
o) OPTION=${OPTARG};;
m) MODEL_PATH=${OPTARG};;
p) PERF_DIR=${OPTARG};;
e) EP_LIST=${OPTARG};;
esac
done
# Variables
DOCKER_PERF_DIR=/usr/share/perf/
PERF_SCRIPT=$DOCKER_PERF_DIR'perf.sh'
VOLUME=$PERF_DIR:$DOCKER_PERF_DIR
ONNX_ZOO_VOLUME=' -v /home/hcsuser/perf/models:/usr/share/perf/models'
MANY_MODELS_VOLUME=' -v /home/hcsuser/mount/many-models:/usr/share/mount/many-models'
PARTNER_VOLUME=' -v /home/hcsuser/perf/partner:/usr/share/perf/partner'
DOCKER_PERF_DIR='/perf/'
HOME_PERF_DIR='/home/hcsuser/perf/'
WORKSPACE='/'
MODEL_PATH=$WORKSPACE$MODEL_PATH
# Add Remaining Variables
if [ $OPTION == "onnx-zoo-models" ]
then
MODEL_PATH='model_list.json'
VOLUME=$VOLUME$ONNX_ZOO_VOLUME
fi
if [ $OPTION == "many-models" ]
then
MODEL_PATH=/usr/share/mount/many-models
VOLUME=$VOLUME$MANY_MODELS_VOLUME
fi
if [ $OPTION == "partner-models" ]
then
MODEL_PATH='partner/partner_model_list.json'
VOLUME=$VOLUME$PARTNER_VOLUME
fi
if [ $OPTION == "selected-models" ]
then
VOLUME=$VOLUME$ONNX_ZOO_VOLUME$MANY_MODELS_VOLUME$PARTNER_VOLUME' -v /home/hcsuser/perf/subset_jsons/:/usr/share/perf/subset_jsons'
fi
sudo docker run --gpus all -v $VOLUME $DOCKER_IMAGE /bin/bash $PERF_SCRIPT -d $DOCKER_PERF_DIR -o $OPTION -m $MODEL_PATH
docker run --gpus all -v $PERF_DIR:$DOCKER_PERF_DIR -v $HOME_PERF_DIR$OPTION:$DOCKER_PERF_DIR$OPTION $DOCKER_IMAGE /bin/bash $DOCKER_PERF_DIR'perf.sh' -d $DOCKER_PERF_DIR -o $OPTION -m $MODEL_PATH -w $WORKSPACE -e "$EP_LIST"

View file

@ -1,31 +1,16 @@
#!/bin/bash
# Parse Arguments
while getopts o:m: parameter
while getopts o:m:e: parameter
do case "${parameter}"
in
o) OPTION=${OPTARG};;
m) MODEL_PATH=${OPTARG};;
e) EP_LIST=${OPTARG};;
esac
done
# Variables
PERF_DIR=/home/hcsuser/perf/
WORKSPACE=/home/hcsuser/
# Select models to be tested or run selected-models
if [ $OPTION == "onnx-zoo-models" ]
then
MODEL_PATH='model_list.json'
fi
if [ $OPTION == "many-models" ]
then
MODEL_PATH=/home/hcsuser/mount/many-models
fi
if [ $OPTION == "partner-models" ]
then
MODEL_PATH='partner_model_list.json'
fi
./perf.sh -d $PERF_DIR -o $OPTION -m $MODEL_PATH
./perf.sh -o $OPTION -m $WORKSPACE$MODEL_PATH -w $WORKSPACE -e "$EP_LIST"

View file

@ -1,43 +1,85 @@
jobs:
parameters:
- name: BuildORT
displayName: Build ORT
type: boolean
default: true
- name: PostToDashboard
displayName: Post to Dashboard
type: boolean
default: true
- name: RunDocker
displayName: Run in Docker (CUDA 11.0)
type: boolean
default: false
- name: ConfigureEPs
displayName: Configure EPs (set epList variable - separate by spaces)
type: boolean
default: false
- name: ModelGroups
type: object
default:
- "onnx-zoo-models"
- "many-models"
- "partner-models"
jobs:
- job: Linux_CI_GPU_TENSORRT_PERF
pool: Linux-GPU-TensorRT-Perf
variables:
ALLOW_RELEASED_ONNX_OPSET_ONLY: '1'
branch: 'master'
timeoutInMinutes: 3000
steps:
- script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build/build_image.sh -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build/Dockerfile.tensorrt-perf -b $(branch) -i ort-$(branch)'
displayName: 'Build latest ORT Images'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build'
variables:
- name: environment
${{ if eq(parameters.RunDocker, true) }}:
value: docker.sh -d ort-$(branch) -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf
${{ if ne(parameters.RunDocker, true) }}:
value: machine.sh
- name: with_arguments
value: $(environment) -e "$(epList)"
- name: run_conda
value: eval "$(command conda 'shell.bash' 'hook' 2> /dev/null)" && conda activate perf3.8
timeoutInMinutes: 3000
steps:
- script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/run_perf_docker.sh -d ort-$(branch) -o "onnx-zoo-models" -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf'
displayName: 'Onnx Zoo Models Perf'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
- ${{ if eq(parameters.BuildORT, true) }}:
- script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/run_perf_docker.sh -d ort-$(branch) -o "many-models" -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf'
displayName: 'Many Models Perf'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
- script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/run_perf_docker.sh -d ort-$(branch) -o "partner-models" -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf'
displayName: 'Partner Models Perf'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
- script: 'mkdir $(Build.SourcesDirectory)/Artifact && cp -r $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/result/ $(Build.SourcesDirectory)/Artifact'
displayName: 'Prepare Artifacts'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/Artifact'
artifactName: 'result'
- ${{ if eq(parameters.RunDocker, true) }}:
- script: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build/build_image.sh -p $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build/Dockerfile.tensorrt-perf -b $(branch) -i ort-$(branch)'
displayName: 'Build latest ORT Images'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build'
- ${{ if eq(parameters.RunDocker, false) }}:
- script: '$(run_conda) && python3 $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build/ort_build_latest.py -b $(branch) -c /usr/local/cuda -o ~/repos/onnxruntime/ -t ~/TensorRT-7.2.2.3'
displayName: 'Build latest ORT'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/build'
- ${{ each option in parameters.ModelGroups }}:
- script: '$(run_conda) && $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/run_perf_$(with_arguments) -o ${{option}} -m $(${{option}})'
displayName: '${{option}} perf'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
env:
LD_LIBRARY_PATH : "/home/hcsuser/TensorRT-7.2.2.3/lib"
- ${{ if not(eq(length(parameters.ModelGroups), 0)) }}:
- script: 'mkdir $(Build.SourcesDirectory)/Artifact && cp -r $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/result/ $(Build.SourcesDirectory)/Artifact'
displayName: 'Prepare Artifacts'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/Artifact'
artifactName: 'result'
- script: 'python3 $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/post.py -r $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/result -c $(Build.SourceVersion) -u "https://dev.azure.com/onnxruntime/onnxruntime/_build/results?buildId=$(Build.BuildId)" '
displayName: 'Post to Dashboard'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
env:
DASHBOARD_MYSQL_ORT_PASSWORD: $(dashboard-mysql-ort-password)
- ${{ if eq(parameters.PostToDashboard, true) }}:
- script: '$(run_conda) && python3 $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/post.py -r $(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/result -c $(Build.SourceVersion) -u "https://dev.azure.com/onnxruntime/onnxruntime/_build/results?buildId=$(Build.BuildId)" '
displayName: 'Post to Dashboard'
workingDirectory: '$(Build.SourcesDirectory)/onnxruntime/python/tools/tensorrt/perf/'
env:
DASHBOARD_MYSQL_ORT_PASSWORD: $(dashboard-mysql-ort-password)
- script: sudo rm -rf $(Agent.BuildDirectory)
displayName: Clean build files (POSIX)