+++ /dev/null
-
-platform :ios, '12.0'
-target 'TestApp' do
- pod 'LibTorch'
-end
## TestApp
-The TestApp is being used for different purposes as described below
-
-### Cocoapods
-
-To quickly test our framework in Cocoapods, simply run
-
-```ruby
-pod install
-```
-
-This will pull the latest version of `LibTorch` from Cocoapods. To run the app, you need to have your model copied to the project as well as a `config.json` file, which can be found in the benchmark folder.
-
-### Circle CI and Fastlane
-
The TestApp is currently being used as a dummy app by Circle CI for nightly jobs. The challenge comes when testing the arm64 build as we don't have a way to code-sign our TestApp. This is where Fastlane came to rescue. [Fastlane](https://fastlane.tools/) is a trendy automation tool for building and managing iOS applications. It also works seamlessly with Circle CI. We are going to leverage the `import_certificate` action, which can install developer certificates on CI machines. See `Fastfile` for more details.
For simulator build, we run unit tests as the last step of our CI workflow. Those unit tests can also be run manually via the `fastlane scan` command.
-
-### Benchmark
-
-The benchmark folder contains two scripts that help you setup the benchmark project. The `setup.rb` does the heavy-lifting jobs of setting up the XCode project, whereas the `trace_model.py` is a Python script that you can tweak to generate your model for benchmarking. Simply follow the steps below to setup the project
-
-1. In the PyTorch root directory, run `IOS_ARCH=arm64 ./scripts/build_ios.sh` to generate the custom build from **Master** branch
-2. Navigate to the `benchmark` folder, run `python trace_model.py` to generate your model.
-3. In the same directory, open `config.json`. Those are the input parameters you can tweak.
-4. Again, in the same directory, run `ruby setup.rb` to setup the XCode project.
-5. Open the `TestApp.xcodeproj`, you're ready to go.
-
-The benchmark code is written in C++, you can use `UI_LOG` to visualize the log. See `benchmark.mm` for more details.
-
-### `bootstrap.sh`
-
-For those who want to do perf testing but don't want to touch XCode, `bootstrap.sh` is the right tool for you. It'll automatically build and install the app on your device. That being said, it does require you to have
-
-1. A valid iOS dev certificate installed on your local machine.
-2. A valid provisioning profile for code signing
-3. A valid team identifier
-
-To run the script, simply type the command below and make sure your phone is connected via USB.
-
-```shell
-./bootstrap
-```
-
-Open the app on your device, the benchmark result will be displayed on the screen.
-
-> Note This requires ios-deploy to be installed. Please have a look at [ios-deploy](https://github.com/ios-control/ios-deploy). To quickly install it, use `npm -g i ios-deploy`
objects = {
/* Begin PBXBuildFile section */
- A03C2960235EA3C1000B4408 /* Benchmark.mm in Sources */ = {isa = PBXBuildFile; fileRef = A03C295F235EA3C1000B4408 /* Benchmark.mm */; };
A06D4CB5232F0DB200763E16 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A06D4CB4232F0DB200763E16 /* AppDelegate.m */; };
A06D4CB8232F0DB200763E16 /* ViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = A06D4CB7232F0DB200763E16 /* ViewController.mm */; };
A06D4CBB232F0DB200763E16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A06D4CB9232F0DB200763E16 /* Main.storyboard */; };
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- A03C295E235EA3C0000B4408 /* Benchmark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Benchmark.h; sourceTree = "<group>"; };
- A03C295F235EA3C1000B4408 /* Benchmark.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Benchmark.mm; sourceTree = "<group>"; };
A06D4CB0232F0DB200763E16 /* TestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
A06D4CB3232F0DB200763E16 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
A06D4CB4232F0DB200763E16 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
A06D4CB2232F0DB200763E16 /* TestApp */ = {
isa = PBXGroup;
children = (
- A03C295E235EA3C0000B4408 /* Benchmark.h */,
- A03C295F235EA3C1000B4408 /* Benchmark.mm */,
A06D4CB3232F0DB200763E16 /* AppDelegate.h */,
A06D4CB4232F0DB200763E16 /* AppDelegate.m */,
A06D4CB6232F0DB200763E16 /* ViewController.h */,
A06D4CB8232F0DB200763E16 /* ViewController.mm in Sources */,
A06D4CC3232F0DB200763E16 /* main.m in Sources */,
A06D4CB5232F0DB200763E16 /* AppDelegate.m in Sources */,
- A03C2960235EA3C1000B4408 /* Benchmark.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
+++ /dev/null
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface Benchmark : NSObject
-
-+ (BOOL)setup:(NSDictionary* )config;
-+ (NSString* )run;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-#import "Benchmark.h"
-#include <string>
-#include <vector>
-#include "torch/script.h"
-
-#include <torch/csrc/jit/mobile/function.h>
-#include <torch/csrc/jit/mobile/import.h>
-#include <torch/csrc/jit/mobile/interpreter.h>
-#include <torch/csrc/jit/mobile/module.h>
-#include <torch/csrc/jit/mobile/observer.h>
-#include "ATen/ATen.h"
-#include "caffe2/core/timer.h"
-#include "caffe2/utils/string_utils.h"
-#include "torch/csrc/autograd/grad_mode.h"
-
-static std::string model = "model.ptl";
-static std::string input_dims = "1,3,224,224";
-static std::string input_type = "float";
-static BOOL print_output = false;
-static int warmup = 10;
-static int iter = 10;
-
-@implementation Benchmark
-
-+ (BOOL)setup:(NSDictionary*)config {
- NSString* modelPath = [[NSBundle mainBundle] pathForResource:@"model" ofType:@"ptl"];
- if (![[NSFileManager defaultManager] fileExistsAtPath:modelPath]) {
- NSLog(@"model.ptl doesn't exist!");
- return NO;
- }
- model = std::string(modelPath.UTF8String);
- input_dims = std::string(((NSString*)config[@"input_dims"]).UTF8String);
- input_type = std::string(((NSString*)config[@"input_type"]).UTF8String);
- warmup = ((NSNumber*)config[@"warmup"]).intValue;
- iter = ((NSNumber*)config[@"iter"]).intValue;
- print_output = ((NSNumber*)config[@"print_output"]).boolValue;
- return YES;
-}
-
-+ (NSString*)run {
- std::vector<std::string> logs;
-#define UI_LOG(fmt, ...) \
- { \
- NSString* log = [NSString stringWithFormat:fmt, __VA_ARGS__]; \
- NSLog(@"%@", log); \
- logs.push_back(log.UTF8String); \
- }
-
- CAFFE_ENFORCE_GE(input_dims.size(), 0, "Input dims must be specified.");
- CAFFE_ENFORCE_GE(input_type.size(), 0, "Input type must be specified.");
-
- std::vector<std::string> input_dims_list = caffe2::split(';', input_dims);
- std::vector<std::string> input_type_list = caffe2::split(';', input_type);
- CAFFE_ENFORCE_EQ(input_dims_list.size(), input_type_list.size(),
- "Input dims and type should have the same number of items.");
-
- std::vector<c10::IValue> inputs;
- for (size_t i = 0; i < input_dims_list.size(); ++i) {
- auto input_dims_str = caffe2::split(',', input_dims_list[i]);
- std::vector<int64_t> input_dims;
- for (const auto& s : input_dims_str) {
- input_dims.push_back(c10::stoi(s));
- }
- if (input_type_list[i] == "float") {
- inputs.push_back(torch::ones(input_dims, at::ScalarType::Float));
- } else if (input_type_list[i] == "uint8_t") {
- inputs.push_back(torch::ones(input_dims, at::ScalarType::Byte));
- } else {
- CAFFE_THROW("Unsupported input type: ", input_type_list[i]);
- }
- }
-
- c10::InferenceMode mode;
- auto module = torch::jit::_load_for_mobile(model);
-
-// module.eval();
- if (print_output) {
- std::cout << module.forward(inputs) << std::endl;
- }
- UI_LOG(@"Running warmup runs", nil);
- CAFFE_ENFORCE(warmup >= 0, "Number of warm up runs should be non negative, provided ", warmup,
- ".");
- for (int i = 0; i < warmup; ++i) {
- module.forward(inputs);
- }
- UI_LOG(@"Main runs", nil);
- CAFFE_ENFORCE(iter >= 0, "Number of main runs should be non negative, provided ", iter, ".");
- caffe2::Timer timer;
- auto millis = timer.MilliSeconds();
- for (int i = 0; i < iter; ++i) {
- module.forward(inputs);
- }
- millis = timer.MilliSeconds();
- UI_LOG(@"Main run finished. Milliseconds per iter: %.3f", millis / iter, nil);
- UI_LOG(@"Iters per second: : %.3f", 1000.0 * iter / millis, nil);
- UI_LOG(@"Done.", nil);
-
- NSString* results = @"";
- for (auto& msg : logs) {
- results = [results stringByAppendingString:[NSString stringWithUTF8String:msg.c_str()]];
- results = [results stringByAppendingString:@"\n"];
- }
- return results;
-}
-
-@end
#import "ViewController.h"
-#import <torch/script.h>
-#import "Benchmark.h"
@interface ViewController ()
-@property(weak, nonatomic) IBOutlet UITextView* textView;
-
@end
-@implementation ViewController {
-}
-
-- (void)viewDidLoad {
- [super viewDidLoad];
-
- NSError* err;
- NSData* configData = [NSData
- dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"config" ofType:@"json"]];
- if (!configData) {
- NSLog(@"Config.json not found!");
- return;
- }
- NSDictionary* config = [NSJSONSerialization JSONObjectWithData:configData
- options:NSJSONReadingAllowFragments
- error:&err];
-
- if (err) {
- NSLog(@"Parse config.json failed!");
- return;
- }
- [Benchmark setup:config];
- [self runBenchmark];
-}
-
-- (void)runBenchmark {
- self.textView.text = @"Start benchmarking...\n";
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSString* text = [Benchmark run];
- dispatch_async(dispatch_get_main_queue(), ^{
- self.textView.text = [self.textView.text stringByAppendingString:text];
- });
- });
-}
-
-- (IBAction)reRun:(id)sender {
- self.textView.text = @"";
- dispatch_async(dispatch_get_main_queue(), ^{
- [self runBenchmark];
- });
-}
-
+@implementation ViewController
@end
+++ /dev/null
-{
- "input_dims": "1,3,224,224",
- "input_type": "float",
- "warmup": 10,
- "iter": 10,
- "print_output": false
-}
if not File.exist?(model_path)
raise "model.pt can't be found!"
end
-config_path = File.expand_path("./config.json")
-if not File.exist?(config_path)
- raise "config.json can't be found!"
- end
+
group = project.main_group.find_subpath(File.join('TestApp'),true)
group.set_source_tree('SOURCE_ROOT')
group.files.each do |file|
- if (file.name.to_s.end_with?(".pt") || file.name == "config.json")
+ if (file.name.to_s.end_with?(".pt"))
group.remove_reference(file)
targets.each do |target|
target.resources_build_phase.remove_file_reference(file)
end
end
model_file_ref = group.new_reference(model_path)
-config_file_ref = group.new_reference(config_path)
targets.each do |target|
target.resources_build_phase.add_file_reference(model_file_ref, true)
- target.resources_build_phase.add_file_reference(config_file_ref, true)
end
puts "Linking static libraries..."
libs = ['libc10.a', 'libclog.a', 'libpthreadpool.a', 'libXNNPACK.a', 'libeigen_blas.a', 'libcpuinfo.a', 'libpytorch_qnnpack.a', 'libtorch_cpu.a', 'libtorch.a']
+++ /dev/null
-#!/bin/bash
-set -e
-
-echo "Current Dir: $(pwd)"
-if [[ "$OSTYPE" != *"darwin"* ]];then
- error "Current OS Type is not MacOS"
- sleep 1
- exit 1
-fi
-BIN_NAME=$(basename "$0")
-help () {
- echo "Usage: $BIN_NAME <options>"
- echo
- echo "Options:"
- echo " -t Team Identifier"
- echo " -p Name of the Provisioning Profile"
-}
-bootstrap() {
- echo "starting"
- echo "detecting devices..."
- if ! [ -x "$(command -v ios-deploy)" ]; then
- echo 'Error: ios-deploy is not installed.'
- exit 1
- fi
- ios-deploy -c -t 1
- if [ "$?" -ne "0" ]; then
- echo 'Error: No device connected. Please connect your device via USB then re-run the script'
- exit 1
- fi
- echo "Done."
- PROJ_ROOT=$(pwd)
- BENCHMARK_DIR="${PROJ_ROOT}/benchmark"
- XCODE_PROJ_PATH="./TestApp.xcodeproj"
- XCODE_TARGET="TestApp"
- XCODE_BUILD="./build"
- if [ ! -f "./.config" ]; then
- touch .config
- echo "" >> .config
- else
- source .config
- fi
- if [ -z "${TEAM_ID}" ]; then
- reply=$(bash -c 'read -r -p "Team Id:" tmp; echo $tmp')
- TEAM_ID="${reply}"
- echo "TEAM_ID=${TEAM_ID}" >> .config
- fi
- if [ -z "${PROFILE}" ]; then
- reply=$(bash -c 'read -r -p "Provisioning Profile:" tmp; echo $tmp')
- PROFILE="${reply}"
- echo "PROFILE=${PROFILE}" >> .config
- fi
- if [ -d "${XCODE_BUILD}" ]; then
- echo "found the old XCode build, remove it"
- rm -rf "${XCODE_BUILD}"
- fi
- cd "${BENCHMARK_DIR}"
- echo "Generating model"
- python trace_model.py
- ruby setup.rb -t "${TEAM_ID}"
- cd ..
- #run xcodebuild
- if ! [ -x "$(command -v xcodebuild)" ]; then
- echo 'Error: xcodebuild is not installed.'
- exit 1
- fi
- echo "Running xcodebuild"
- xcodebuild clean build -project ${XCODE_PROJ_PATH} \
- -target ${XCODE_TARGET} \
- -sdk iphoneos \
- -configuration Debug \
- PROVISIONING_PROFILE_SPECIFIER=${PROFILE}
- #install TestApp
- echo "installing..."
- ios-deploy -r --bundle "${XCODE_BUILD}/Debug-iphoneos/${XCODE_TARGET}.app"
- echo "Done."
-}
-while [[ $# -gt 1 ]]
-do
-option="$1"
-value="$2"
-case $option in
- "" | "-h" | "--help")
- help
- exit 0
- ;;
- "-t" | "--team")
- TEAM_ID="${value}"
- shift
- ;;
- "-p"|"--profile")
- PROFILE="${value}"
- shift
- ;;
- *)
- echo "unknown options" >& 2
- help
- exit 1
- ;;
-esac
-shift
-done
-
-bootstrap