diff --git a/infra/bots/gen_tasks.go b/infra/bots/gen_tasks.go index d10b364e8a..dcb021c096 100644 --- a/infra/bots/gen_tasks.go +++ b/infra/bots/gen_tasks.go @@ -1135,6 +1135,8 @@ func perf(b *specs.TasksCfgBuilder, name string, parts map[string]string, compil if strings.Contains(parts["extra_config"], "Skpbench") { recipe = "skpbench" isolate = relpath("skpbench_skia_bundled.isolate") + } else if strings.Contains(name, "PathKit") { + recipe = "perf_pathkit" } task := kitchenTask(name, recipe, isolate, "", swarmDimensions(parts), nil, OUTPUT_PERF) task.CipdPackages = append(task.CipdPackages, pkgs...) diff --git a/infra/bots/jobs.json b/infra/bots/jobs.json index cf1044995b..8fd6810135 100644 --- a/infra/bots/jobs.json +++ b/infra/bots/jobs.json @@ -221,6 +221,8 @@ "Perf-Debian9-Clang-NUCDE3815TYKHE-GPU-IntelBayTrail-x86_64-Release-All", "Perf-Debian9-Clang-ShuttleA-GPU-IntelHD2000-x86_64-Debug-All", "Perf-Debian9-Clang-ShuttleA-GPU-IntelHD2000-x86_64-Release-All", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit", "Perf-Debian9-GCC-GCE-CPU-AVX2-x86-Debug-All", "Perf-Debian9-GCC-GCE-CPU-AVX2-x86_64-Debug-All", "Perf-Mac-Clang-MacBook10.1-GPU-IntelHD615-x86_64-Debug-All", diff --git a/infra/bots/recipes/perf_pathkit.expected/Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit.json b/infra/bots/recipes/perf_pathkit.expected/Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit.json new file mode 100644 index 0000000000..3cde98baee --- /dev/null +++ b/infra/bots/recipes/perf_pathkit.expected/Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit.json @@ -0,0 +1,235 @@ +[ + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "ensure-directory", + "--mode", + "0777", + "[START_DIR]/cache/work" + ], + "infra_step": true, + "name": "makedirs checkout_path" + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "remove", + "[START_DIR]/cache/work/.gclient_entries" + ], + "infra_step": true, + "name": "remove [START_DIR]/cache/work/.gclient_entries" + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py", + "--spec-path", + "cache_dir = '[START_DIR]/cache/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'skia', 'url': 'https://skia.googlesource.com/skia.git'}]", + "--patch_root", + "skia", + "--revision_mapping_file", + "{\"got_revision\": \"skia\"}", + "--git-cache-dir", + "[START_DIR]/cache/git", + "--cleanup-dir", + "[CLEANUP]/bot_update", + "--output_json", + "/path/to/tmp/json", + "--revision", + "skia@abc123" + ], + "cwd": "[START_DIR]/cache/work", + "env_prefixes": { + "PATH": [ + "RECIPE_PACKAGE_REPO[depot_tools]" + ] + }, + "infra_step": true, + "name": "bot_update", + "~followup_annotations": [ + "@@@STEP_TEXT@Some step text@@@", + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"did_run\": true, @@@", + "@@@STEP_LOG_LINE@json.output@ \"fixed_revisions\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": \"abc123\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"manifest\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"repository\": \"https://fake.org/skia.git\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"patch_failure\": false, @@@", + "@@@STEP_LOG_LINE@json.output@ \"patch_root\": \"skia\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"properties\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"got_revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"got_revision_cp\": \"refs/heads/master@{#164710}\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"root\": \"skia\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"source_manifest\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"directories\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"git_checkout\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"repo_url\": \"https://fake.org/skia.git\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"version\": 0@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"step_text\": \"Some step text\"@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@", + "@@@SET_BUILD_PROPERTY@got_revision@\"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@SET_BUILD_PROPERTY@got_revision_cp@\"refs/heads/master@{#164710}\"@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "ensure-directory", + "--mode", + "0777", + "[START_DIR]/[SWARM_OUT_DIR]" + ], + "infra_step": true, + "name": "mkdirs out_dir" + }, + { + "cmd": [ + "python", + "-u", + "import errno\nimport os\nimport shutil\nimport sys\n\ncopy_dest = sys.argv[1]\nbase_dir = sys.argv[2]\nbundle_name = sys.argv[3]\nout_dir = sys.argv[4]\n\n# Clean out old binaries (if any)\ntry:\n shutil.rmtree(copy_dest)\nexcept OSError as e:\n if e.errno != errno.ENOENT:\n raise\n\n# Make folder\ntry:\n os.makedirs(copy_dest)\nexcept OSError as e:\n if e.errno != errno.EEXIST:\n raise\n\n# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests\n# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/)\ndest = os.path.join(copy_dest, 'pathkit.js')\nshutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest)\nos.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.\n\nif bundle_name:\n dest = os.path.join(copy_dest, bundle_name)\n shutil.copyfile(os.path.join(base_dir, bundle_name), dest)\n os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.\n\n# Prepare output folder, api.file.ensure_directory doesn't touch\n# the permissions of the out directory if it already exists.\nos.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write.\n", + "[START_DIR]/cache/work/skia/modules/pathkit/npm-asmjs/bin", + "[START_DIR]/build", + "pathkit.js.mem", + "[START_DIR]/[SWARM_OUT_DIR]" + ], + "infra_step": true, + "name": "Set up for docker", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import errno@@@", + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@import shutil@@@", + "@@@STEP_LOG_LINE@python.inline@import sys@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@copy_dest = sys.argv[1]@@@", + "@@@STEP_LOG_LINE@python.inline@base_dir = sys.argv[2]@@@", + "@@@STEP_LOG_LINE@python.inline@bundle_name = sys.argv[3]@@@", + "@@@STEP_LOG_LINE@python.inline@out_dir = sys.argv[4]@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Clean out old binaries (if any)@@@", + "@@@STEP_LOG_LINE@python.inline@try:@@@", + "@@@STEP_LOG_LINE@python.inline@ shutil.rmtree(copy_dest)@@@", + "@@@STEP_LOG_LINE@python.inline@except OSError as e:@@@", + "@@@STEP_LOG_LINE@python.inline@ if e.errno != errno.ENOENT:@@@", + "@@@STEP_LOG_LINE@python.inline@ raise@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Make folder@@@", + "@@@STEP_LOG_LINE@python.inline@try:@@@", + "@@@STEP_LOG_LINE@python.inline@ os.makedirs(copy_dest)@@@", + "@@@STEP_LOG_LINE@python.inline@except OSError as e:@@@", + "@@@STEP_LOG_LINE@python.inline@ if e.errno != errno.EEXIST:@@@", + "@@@STEP_LOG_LINE@python.inline@ raise@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests@@@", + "@@@STEP_LOG_LINE@python.inline@# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/)@@@", + "@@@STEP_LOG_LINE@python.inline@dest = os.path.join(copy_dest, 'pathkit.js')@@@", + "@@@STEP_LOG_LINE@python.inline@shutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest)@@@", + "@@@STEP_LOG_LINE@python.inline@os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@if bundle_name:@@@", + "@@@STEP_LOG_LINE@python.inline@ dest = os.path.join(copy_dest, bundle_name)@@@", + "@@@STEP_LOG_LINE@python.inline@ shutil.copyfile(os.path.join(base_dir, bundle_name), dest)@@@", + "@@@STEP_LOG_LINE@python.inline@ os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Prepare output folder, api.file.ensure_directory doesn't touch@@@", + "@@@STEP_LOG_LINE@python.inline@# the permissions of the out directory if it already exists.@@@", + "@@@STEP_LOG_LINE@python.inline@os.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write.@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "import os\nprint os.environ.get('SWARMING_BOT_ID', '')\n" + ], + "name": "get swarming bot id", + "stdout": "/path/to/tmp/", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_BOT_ID', '')@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "import os\nprint os.environ.get('SWARMING_TASK_ID', '')\n" + ], + "name": "get swarming task id", + "stdout": "/path/to/tmp/", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_TASK_ID', '')@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "docker", + "run", + "--shm-size=2gb", + "--rm", + "-v", + "[START_DIR]/cache/work:/SRC", + "-v", + "[START_DIR]/[SWARM_OUT_DIR]:/OUT", + "-e", + "ASM_JS=1", + "gcr.io/skia-public/perf-karma-chrome-tests:68.0.3440.106_v1", + "/SRC/skia/infra/pathkit/perf_pathkit.sh", + "--builder", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit", + "--git_hash", + "abc123", + "--buildbucket_build_id", + "", + "--bot_id", + "", + "--task_id", + "", + "--browser", + "Chrome", + "--config", + "Release", + "--compiled_language", + "asmjs" + ], + "env": { + "CHROME_HEADLESS": "1", + "PATH": ":RECIPE_PACKAGE_REPO[depot_tools]" + }, + "name": "Performance tests of PathKit with Docker" + }, + { + "name": "$result", + "recipe_result": null, + "status_code": 0 + } +] \ No newline at end of file diff --git a/infra/bots/recipes/perf_pathkit.expected/Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit.json b/infra/bots/recipes/perf_pathkit.expected/Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit.json new file mode 100644 index 0000000000..96ff4a37bf --- /dev/null +++ b/infra/bots/recipes/perf_pathkit.expected/Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit.json @@ -0,0 +1,231 @@ +[ + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "ensure-directory", + "--mode", + "0777", + "[START_DIR]/cache/work" + ], + "infra_step": true, + "name": "makedirs checkout_path" + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "remove", + "[START_DIR]/cache/work/.gclient_entries" + ], + "infra_step": true, + "name": "remove [START_DIR]/cache/work/.gclient_entries" + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py", + "--spec-path", + "cache_dir = '[START_DIR]/cache/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'skia', 'url': 'https://skia.googlesource.com/skia.git'}]", + "--patch_root", + "skia", + "--revision_mapping_file", + "{\"got_revision\": \"skia\"}", + "--git-cache-dir", + "[START_DIR]/cache/git", + "--cleanup-dir", + "[CLEANUP]/bot_update", + "--output_json", + "/path/to/tmp/json", + "--revision", + "skia@abc123" + ], + "cwd": "[START_DIR]/cache/work", + "env_prefixes": { + "PATH": [ + "RECIPE_PACKAGE_REPO[depot_tools]" + ] + }, + "infra_step": true, + "name": "bot_update", + "~followup_annotations": [ + "@@@STEP_TEXT@Some step text@@@", + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"did_run\": true, @@@", + "@@@STEP_LOG_LINE@json.output@ \"fixed_revisions\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": \"abc123\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"manifest\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"repository\": \"https://fake.org/skia.git\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"patch_failure\": false, @@@", + "@@@STEP_LOG_LINE@json.output@ \"patch_root\": \"skia\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"properties\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"got_revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"got_revision_cp\": \"refs/heads/master@{#164710}\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"root\": \"skia\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"source_manifest\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"directories\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"git_checkout\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"repo_url\": \"https://fake.org/skia.git\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"version\": 0@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"step_text\": \"Some step text\"@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@", + "@@@SET_BUILD_PROPERTY@got_revision@\"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@SET_BUILD_PROPERTY@got_revision_cp@\"refs/heads/master@{#164710}\"@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "ensure-directory", + "--mode", + "0777", + "[START_DIR]/[SWARM_OUT_DIR]" + ], + "infra_step": true, + "name": "mkdirs out_dir" + }, + { + "cmd": [ + "python", + "-u", + "import errno\nimport os\nimport shutil\nimport sys\n\ncopy_dest = sys.argv[1]\nbase_dir = sys.argv[2]\nbundle_name = sys.argv[3]\nout_dir = sys.argv[4]\n\n# Clean out old binaries (if any)\ntry:\n shutil.rmtree(copy_dest)\nexcept OSError as e:\n if e.errno != errno.ENOENT:\n raise\n\n# Make folder\ntry:\n os.makedirs(copy_dest)\nexcept OSError as e:\n if e.errno != errno.EEXIST:\n raise\n\n# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests\n# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/)\ndest = os.path.join(copy_dest, 'pathkit.js')\nshutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest)\nos.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.\n\nif bundle_name:\n dest = os.path.join(copy_dest, bundle_name)\n shutil.copyfile(os.path.join(base_dir, bundle_name), dest)\n os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.\n\n# Prepare output folder, api.file.ensure_directory doesn't touch\n# the permissions of the out directory if it already exists.\nos.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write.\n", + "[START_DIR]/cache/work/skia/modules/pathkit/npm-wasm/bin", + "[START_DIR]/build", + "pathkit.wasm", + "[START_DIR]/[SWARM_OUT_DIR]" + ], + "infra_step": true, + "name": "Set up for docker", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import errno@@@", + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@import shutil@@@", + "@@@STEP_LOG_LINE@python.inline@import sys@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@copy_dest = sys.argv[1]@@@", + "@@@STEP_LOG_LINE@python.inline@base_dir = sys.argv[2]@@@", + "@@@STEP_LOG_LINE@python.inline@bundle_name = sys.argv[3]@@@", + "@@@STEP_LOG_LINE@python.inline@out_dir = sys.argv[4]@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Clean out old binaries (if any)@@@", + "@@@STEP_LOG_LINE@python.inline@try:@@@", + "@@@STEP_LOG_LINE@python.inline@ shutil.rmtree(copy_dest)@@@", + "@@@STEP_LOG_LINE@python.inline@except OSError as e:@@@", + "@@@STEP_LOG_LINE@python.inline@ if e.errno != errno.ENOENT:@@@", + "@@@STEP_LOG_LINE@python.inline@ raise@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Make folder@@@", + "@@@STEP_LOG_LINE@python.inline@try:@@@", + "@@@STEP_LOG_LINE@python.inline@ os.makedirs(copy_dest)@@@", + "@@@STEP_LOG_LINE@python.inline@except OSError as e:@@@", + "@@@STEP_LOG_LINE@python.inline@ if e.errno != errno.EEXIST:@@@", + "@@@STEP_LOG_LINE@python.inline@ raise@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests@@@", + "@@@STEP_LOG_LINE@python.inline@# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/)@@@", + "@@@STEP_LOG_LINE@python.inline@dest = os.path.join(copy_dest, 'pathkit.js')@@@", + "@@@STEP_LOG_LINE@python.inline@shutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest)@@@", + "@@@STEP_LOG_LINE@python.inline@os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@if bundle_name:@@@", + "@@@STEP_LOG_LINE@python.inline@ dest = os.path.join(copy_dest, bundle_name)@@@", + "@@@STEP_LOG_LINE@python.inline@ shutil.copyfile(os.path.join(base_dir, bundle_name), dest)@@@", + "@@@STEP_LOG_LINE@python.inline@ os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Prepare output folder, api.file.ensure_directory doesn't touch@@@", + "@@@STEP_LOG_LINE@python.inline@# the permissions of the out directory if it already exists.@@@", + "@@@STEP_LOG_LINE@python.inline@os.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write.@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "import os\nprint os.environ.get('SWARMING_BOT_ID', '')\n" + ], + "name": "get swarming bot id", + "stdout": "/path/to/tmp/", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_BOT_ID', '')@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "import os\nprint os.environ.get('SWARMING_TASK_ID', '')\n" + ], + "name": "get swarming task id", + "stdout": "/path/to/tmp/", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_TASK_ID', '')@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "docker", + "run", + "--shm-size=2gb", + "--rm", + "-v", + "[START_DIR]/cache/work:/SRC", + "-v", + "[START_DIR]/[SWARM_OUT_DIR]:/OUT", + "gcr.io/skia-public/perf-karma-chrome-tests:68.0.3440.106_v1", + "/SRC/skia/infra/pathkit/perf_pathkit.sh", + "--builder", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit", + "--git_hash", + "abc123", + "--buildbucket_build_id", + "", + "--bot_id", + "", + "--task_id", + "", + "--browser", + "Chrome", + "--config", + "Release" + ], + "env": { + "CHROME_HEADLESS": "1", + "PATH": ":RECIPE_PACKAGE_REPO[depot_tools]" + }, + "name": "Performance tests of PathKit with Docker" + }, + { + "name": "$result", + "recipe_result": null, + "status_code": 0 + } +] \ No newline at end of file diff --git a/infra/bots/recipes/perf_pathkit.expected/pathkit_trybot.json b/infra/bots/recipes/perf_pathkit.expected/pathkit_trybot.json new file mode 100644 index 0000000000..82187e67ea --- /dev/null +++ b/infra/bots/recipes/perf_pathkit.expected/pathkit_trybot.json @@ -0,0 +1,239 @@ +[ + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "ensure-directory", + "--mode", + "0777", + "[START_DIR]/cache/work" + ], + "infra_step": true, + "name": "makedirs checkout_path" + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "remove", + "[START_DIR]/cache/work/.gclient_entries" + ], + "infra_step": true, + "name": "remove [START_DIR]/cache/work/.gclient_entries" + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[depot_tools::bot_update]/resources/bot_update.py", + "--spec-path", + "cache_dir = '[START_DIR]/cache/git'\nsolutions = [{'deps_file': '.DEPS.git', 'managed': False, 'name': 'skia', 'url': 'https://skia.googlesource.com/skia.git'}]", + "--patch_root", + "skia", + "--revision_mapping_file", + "{\"got_revision\": \"skia\"}", + "--git-cache-dir", + "[START_DIR]/cache/git", + "--cleanup-dir", + "[CLEANUP]/bot_update", + "--output_json", + "/path/to/tmp/json", + "--patch_ref", + "https://skia.googlesource.com/skia.git@89/456789/12", + "--revision", + "skia@abc123" + ], + "cwd": "[START_DIR]/cache/work", + "env_prefixes": { + "PATH": [ + "RECIPE_PACKAGE_REPO[depot_tools]" + ] + }, + "infra_step": true, + "name": "bot_update", + "~followup_annotations": [ + "@@@STEP_TEXT@Some step text@@@", + "@@@STEP_LOG_LINE@json.output@{@@@", + "@@@STEP_LOG_LINE@json.output@ \"did_run\": true, @@@", + "@@@STEP_LOG_LINE@json.output@ \"fixed_revisions\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": \"abc123\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"manifest\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"repository\": \"https://fake.org/skia.git\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"patch_failure\": false, @@@", + "@@@STEP_LOG_LINE@json.output@ \"patch_root\": \"skia\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"properties\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"got_revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"got_revision_cp\": \"refs/heads/master@{#164710}\"@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"root\": \"skia\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"source_manifest\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"directories\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"skia\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"git_checkout\": {@@@", + "@@@STEP_LOG_LINE@json.output@ \"repo_url\": \"https://fake.org/skia.git\", @@@", + "@@@STEP_LOG_LINE@json.output@ \"revision\": \"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"version\": 0@@@", + "@@@STEP_LOG_LINE@json.output@ }, @@@", + "@@@STEP_LOG_LINE@json.output@ \"step_text\": \"Some step text\"@@@", + "@@@STEP_LOG_LINE@json.output@}@@@", + "@@@STEP_LOG_END@json.output@@@", + "@@@SET_BUILD_PROPERTY@got_revision@\"9046e2e693bb92a76e972b694580e5d17ad10748\"@@@", + "@@@SET_BUILD_PROPERTY@got_revision_cp@\"refs/heads/master@{#164710}\"@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "RECIPE_MODULE[recipe_engine::file]/resources/fileutil.py", + "--json-output", + "/path/to/tmp/json", + "ensure-directory", + "--mode", + "0777", + "[START_DIR]/[SWARM_OUT_DIR]" + ], + "infra_step": true, + "name": "mkdirs out_dir" + }, + { + "cmd": [ + "python", + "-u", + "import errno\nimport os\nimport shutil\nimport sys\n\ncopy_dest = sys.argv[1]\nbase_dir = sys.argv[2]\nbundle_name = sys.argv[3]\nout_dir = sys.argv[4]\n\n# Clean out old binaries (if any)\ntry:\n shutil.rmtree(copy_dest)\nexcept OSError as e:\n if e.errno != errno.ENOENT:\n raise\n\n# Make folder\ntry:\n os.makedirs(copy_dest)\nexcept OSError as e:\n if e.errno != errno.EEXIST:\n raise\n\n# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests\n# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/)\ndest = os.path.join(copy_dest, 'pathkit.js')\nshutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest)\nos.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.\n\nif bundle_name:\n dest = os.path.join(copy_dest, bundle_name)\n shutil.copyfile(os.path.join(base_dir, bundle_name), dest)\n os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.\n\n# Prepare output folder, api.file.ensure_directory doesn't touch\n# the permissions of the out directory if it already exists.\nos.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write.\n", + "[START_DIR]/cache/work/skia/modules/pathkit/npm-wasm/bin", + "[START_DIR]/build", + "pathkit.wasm", + "[START_DIR]/[SWARM_OUT_DIR]" + ], + "infra_step": true, + "name": "Set up for docker", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import errno@@@", + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@import shutil@@@", + "@@@STEP_LOG_LINE@python.inline@import sys@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@copy_dest = sys.argv[1]@@@", + "@@@STEP_LOG_LINE@python.inline@base_dir = sys.argv[2]@@@", + "@@@STEP_LOG_LINE@python.inline@bundle_name = sys.argv[3]@@@", + "@@@STEP_LOG_LINE@python.inline@out_dir = sys.argv[4]@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Clean out old binaries (if any)@@@", + "@@@STEP_LOG_LINE@python.inline@try:@@@", + "@@@STEP_LOG_LINE@python.inline@ shutil.rmtree(copy_dest)@@@", + "@@@STEP_LOG_LINE@python.inline@except OSError as e:@@@", + "@@@STEP_LOG_LINE@python.inline@ if e.errno != errno.ENOENT:@@@", + "@@@STEP_LOG_LINE@python.inline@ raise@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Make folder@@@", + "@@@STEP_LOG_LINE@python.inline@try:@@@", + "@@@STEP_LOG_LINE@python.inline@ os.makedirs(copy_dest)@@@", + "@@@STEP_LOG_LINE@python.inline@except OSError as e:@@@", + "@@@STEP_LOG_LINE@python.inline@ if e.errno != errno.EEXIST:@@@", + "@@@STEP_LOG_LINE@python.inline@ raise@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests@@@", + "@@@STEP_LOG_LINE@python.inline@# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/)@@@", + "@@@STEP_LOG_LINE@python.inline@dest = os.path.join(copy_dest, 'pathkit.js')@@@", + "@@@STEP_LOG_LINE@python.inline@shutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest)@@@", + "@@@STEP_LOG_LINE@python.inline@os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@if bundle_name:@@@", + "@@@STEP_LOG_LINE@python.inline@ dest = os.path.join(copy_dest, bundle_name)@@@", + "@@@STEP_LOG_LINE@python.inline@ shutil.copyfile(os.path.join(base_dir, bundle_name), dest)@@@", + "@@@STEP_LOG_LINE@python.inline@ os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read.@@@", + "@@@STEP_LOG_LINE@python.inline@@@@", + "@@@STEP_LOG_LINE@python.inline@# Prepare output folder, api.file.ensure_directory doesn't touch@@@", + "@@@STEP_LOG_LINE@python.inline@# the permissions of the out directory if it already exists.@@@", + "@@@STEP_LOG_LINE@python.inline@os.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write.@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "import os\nprint os.environ.get('SWARMING_BOT_ID', '')\n" + ], + "name": "get swarming bot id", + "stdout": "/path/to/tmp/", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_BOT_ID', '')@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "python", + "-u", + "import os\nprint os.environ.get('SWARMING_TASK_ID', '')\n" + ], + "name": "get swarming task id", + "stdout": "/path/to/tmp/", + "~followup_annotations": [ + "@@@STEP_LOG_LINE@python.inline@import os@@@", + "@@@STEP_LOG_LINE@python.inline@print os.environ.get('SWARMING_TASK_ID', '')@@@", + "@@@STEP_LOG_END@python.inline@@@" + ] + }, + { + "cmd": [ + "docker", + "run", + "--shm-size=2gb", + "--rm", + "-v", + "[START_DIR]/cache/work:/SRC", + "-v", + "[START_DIR]/[SWARM_OUT_DIR]:/OUT", + "gcr.io/skia-public/perf-karma-chrome-tests:68.0.3440.106_v1", + "/SRC/skia/infra/pathkit/perf_pathkit.sh", + "--builder", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit", + "--git_hash", + "abc123", + "--buildbucket_build_id", + "", + "--bot_id", + "", + "--task_id", + "", + "--browser", + "Chrome", + "--config", + "Release", + "--issue", + "1234", + "--patchset", + "7", + "--patch_storage", + "gerrit" + ], + "env": { + "CHROME_HEADLESS": "1", + "PATH": ":RECIPE_PACKAGE_REPO[depot_tools]" + }, + "name": "Performance tests of PathKit with Docker" + }, + { + "name": "$result", + "recipe_result": null, + "status_code": 0 + } +] \ No newline at end of file diff --git a/infra/bots/recipes/perf_pathkit.py b/infra/bots/recipes/perf_pathkit.py new file mode 100644 index 0000000000..e0c5495921 --- /dev/null +++ b/infra/bots/recipes/perf_pathkit.py @@ -0,0 +1,162 @@ +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Recipe which runs the PathKit tests using docker + +DEPS = [ + 'checkout', + 'infra', + 'recipe_engine/file', + 'recipe_engine/path', + 'recipe_engine/properties', + 'recipe_engine/python', + 'recipe_engine/step', + 'run', + 'vars', +] + + +DOCKER_IMAGE = 'gcr.io/skia-public/perf-karma-chrome-tests:68.0.3440.106_v1' +INNER_KARMA_SCRIPT = '/SRC/skia/infra/pathkit/perf_pathkit.sh' + + +def RunSteps(api): + api.vars.setup() + checkout_root = api.checkout.default_checkout_root + out_dir = api.vars.swarming_out_dir + api.checkout.bot_update(checkout_root=checkout_root) + + # Make sure this exists, otherwise Docker will make it with root permissions. + api.file.ensure_directory('mkdirs out_dir', out_dir, mode=0777) + + # The karma script is configured to look in ./npm-(asmjs|wasm)/bin/ for + # the test files to load, so we must copy them there (see Set up for docker). + copy_dest = checkout_root.join('skia', 'modules', 'pathkit', + 'npm-wasm', 'bin') + if 'asmjs' in api.vars.builder_name: + copy_dest = checkout_root.join('skia', 'modules', 'pathkit', + 'npm-asmjs', 'bin') + + base_dir = api.vars.build_dir + bundle_name = 'pathkit.wasm' + if 'asmjs' in api.vars.builder_name: + bundle_name = 'pathkit.js.mem' + + api.python.inline( + name='Set up for docker', + program='''import errno +import os +import shutil +import sys + +copy_dest = sys.argv[1] +base_dir = sys.argv[2] +bundle_name = sys.argv[3] +out_dir = sys.argv[4] + +# Clean out old binaries (if any) +try: + shutil.rmtree(copy_dest) +except OSError as e: + if e.errno != errno.ENOENT: + raise + +# Make folder +try: + os.makedirs(copy_dest) +except OSError as e: + if e.errno != errno.EEXIST: + raise + +# Copy binaries (pathkit.js and pathkit.wasm) to where the karma tests +# expect them ($SKIA_ROOT/modules/pathkit/npm-wasm/) +dest = os.path.join(copy_dest, 'pathkit.js') +shutil.copyfile(os.path.join(base_dir, 'pathkit.js'), dest) +os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read. + +if bundle_name: + dest = os.path.join(copy_dest, bundle_name) + shutil.copyfile(os.path.join(base_dir, bundle_name), dest) + os.chmod(dest, 0o644) # important, otherwise non-privileged docker can't read. + +# Prepare output folder, api.file.ensure_directory doesn't touch +# the permissions of the out directory if it already exists. +os.chmod(out_dir, 0o777) # important, otherwise non-privileged docker can't write. +''', + args=[copy_dest, base_dir, bundle_name, out_dir], + infra_step=True) + + + + cmd = ['docker', 'run', '--shm-size=2gb', '--rm', + '-v', '%s:/SRC' % checkout_root, '-v', '%s:/OUT' % out_dir] + + if 'asmjs' in api.vars.builder_name: + cmd.extend(['-e', 'ASM_JS=1']) # -e sets environment variables + + cmd.extend([ + DOCKER_IMAGE, INNER_KARMA_SCRIPT, + '--builder', api.vars.builder_name, + '--git_hash', api.properties['revision'], + '--buildbucket_build_id', api.properties.get('buildbucket_build_id', + ''), + '--bot_id', api.vars.swarming_bot_id, + '--task_id', api.vars.swarming_task_id, + '--browser', 'Chrome', + '--config', api.vars.configuration, + ]) + + if 'asmjs' in api.vars.builder_name: + cmd.extend(['--compiled_language', 'asmjs']) # the default is wasm + + if api.vars.is_trybot: + cmd.extend([ + '--issue', api.vars.issue, + '--patchset', api.vars.patchset, + '--patch_storage', api.vars.patch_storage, + ]) + + api.run( + api.step, + 'Performance tests of PathKit with Docker', + cmd=cmd) + + +def GenTests(api): + yield ( + api.test('Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit') + + api.properties(buildername=('Perf-Debian9-EMCC-GCE-CPU-AVX2' + '-wasm-Release-All-PathKit'), + repository='https://skia.googlesource.com/skia.git', + revision='abc123', + path_config='kitchen', + swarm_out_dir='[SWARM_OUT_DIR]') + ) + + yield ( + api.test('Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit') + + api.properties(buildername=('Perf-Debian9-EMCC-GCE-CPU-AVX2' + '-asmjs-Release-All-PathKit'), + repository='https://skia.googlesource.com/skia.git', + revision='abc123', + path_config='kitchen', + swarm_out_dir='[SWARM_OUT_DIR]') + ) + + yield ( + api.test('pathkit_trybot') + + api.properties(buildername=('Perf-Debian9-EMCC-GCE-CPU-AVX2' + '-wasm-Release-All-PathKit'), + repository='https://skia.googlesource.com/skia.git', + revision='abc123', + path_config='kitchen', + swarm_out_dir='[SWARM_OUT_DIR]', + patch_ref='89/456789/12', + patch_repo='https://skia.googlesource.com/skia.git', + patch_storage='gerrit', + patch_set=7, + patch_issue=1234, + gerrit_project='skia', + gerrit_url='https://skia-review.googlesource.com/') + ) diff --git a/infra/bots/tasks.json b/infra/bots/tasks.json index 413e36a4c6..436b2ce156 100755 --- a/infra/bots/tasks.json +++ b/infra/bots/tasks.json @@ -1121,6 +1121,16 @@ "Upload-Perf-Debian9-Clang-ShuttleA-GPU-IntelHD2000-x86_64-Release-All" ] }, + "Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit": { + "tasks": [ + "Upload-Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit" + ] + }, + "Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit": { + "tasks": [ + "Upload-Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit" + ] + }, "Perf-Debian9-GCC-GCE-CPU-AVX2-x86-Debug-All": { "tasks": [ "Perf-Debian9-GCC-GCE-CPU-AVX2-x86-Debug-All" @@ -28642,6 +28652,200 @@ "perf" ] }, + "Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit": { + "caches": [ + { + "name": "vpython", + "path": "cache/vpython" + } + ], + "cipd_packages": [ + { + "name": "infra/tools/luci/kitchen/${platform}", + "path": ".", + "version": "git_revision:546aae39f1fb9dce9add528e2011afa574535ecd" + }, + { + "name": "infra/tools/luci-auth/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c" + }, + { + "name": "infra/tools/luci/vpython/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:b6cdec8586c9f8d3d728b1bc0bd4331330ba66fc" + } + ], + "command": [ + "./kitchen${EXECUTABLE_SUFFIX}", + "cook", + "-checkout-dir", + "recipe_bundle", + "-mode", + "swarming", + "-luci-system-account", + "system", + "-cache-dir", + "cache", + "-temp-dir", + "tmp", + "-known-gerrit-host", + "android.googlesource.com", + "-known-gerrit-host", + "boringssl.googlesource.com", + "-known-gerrit-host", + "chromium.googlesource.com", + "-known-gerrit-host", + "dart.googlesource.com", + "-known-gerrit-host", + "fuchsia.googlesource.com", + "-known-gerrit-host", + "go.googlesource.com", + "-known-gerrit-host", + "llvm.googlesource.com", + "-known-gerrit-host", + "skia.googlesource.com", + "-known-gerrit-host", + "webrtc.googlesource.com", + "-output-result-json", + "${ISOLATED_OUTDIR}/build_result_filename", + "-workdir", + ".", + "-recipe", + "perf_pathkit", + "-properties", + "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"perf\"}", + "-logdog-annotation-url", + "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + ], + "dependencies": [ + "Housekeeper-PerCommit-BundleRecipes", + "Build-Debian9-EMCC-asmjs-Release-PathKit" + ], + "dimensions": [ + "cpu:x86-64-Haswell_GCE", + "machine_type:n1-standard-16", + "os:Debian-9.4", + "pool:Skia" + ], + "env_prefixes": { + "PATH": [ + "cipd_bin_packages", + "cipd_bin_packages/bin" + ], + "VPYTHON_VIRTUALENV_ROOT": [ + "cache/vpython" + ] + }, + "execution_timeout_ns": 14400000000000, + "expiration_ns": 72000000000000, + "extra_tags": { + "log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + }, + "io_timeout_ns": 14400000000000, + "isolate": "perf_skia_bundled.isolate", + "max_attempts": 1, + "outputs": [ + "perf" + ] + }, + "Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit": { + "caches": [ + { + "name": "vpython", + "path": "cache/vpython" + } + ], + "cipd_packages": [ + { + "name": "infra/tools/luci/kitchen/${platform}", + "path": ".", + "version": "git_revision:546aae39f1fb9dce9add528e2011afa574535ecd" + }, + { + "name": "infra/tools/luci-auth/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c" + }, + { + "name": "infra/tools/luci/vpython/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:b6cdec8586c9f8d3d728b1bc0bd4331330ba66fc" + } + ], + "command": [ + "./kitchen${EXECUTABLE_SUFFIX}", + "cook", + "-checkout-dir", + "recipe_bundle", + "-mode", + "swarming", + "-luci-system-account", + "system", + "-cache-dir", + "cache", + "-temp-dir", + "tmp", + "-known-gerrit-host", + "android.googlesource.com", + "-known-gerrit-host", + "boringssl.googlesource.com", + "-known-gerrit-host", + "chromium.googlesource.com", + "-known-gerrit-host", + "dart.googlesource.com", + "-known-gerrit-host", + "fuchsia.googlesource.com", + "-known-gerrit-host", + "go.googlesource.com", + "-known-gerrit-host", + "llvm.googlesource.com", + "-known-gerrit-host", + "skia.googlesource.com", + "-known-gerrit-host", + "webrtc.googlesource.com", + "-output-result-json", + "${ISOLATED_OUTDIR}/build_result_filename", + "-workdir", + ".", + "-recipe", + "perf_pathkit", + "-properties", + "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"perf\"}", + "-logdog-annotation-url", + "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + ], + "dependencies": [ + "Housekeeper-PerCommit-BundleRecipes", + "Build-Debian9-EMCC-wasm-Release-PathKit" + ], + "dimensions": [ + "cpu:x86-64-Haswell_GCE", + "machine_type:n1-standard-16", + "os:Debian-9.4", + "pool:Skia" + ], + "env_prefixes": { + "PATH": [ + "cipd_bin_packages", + "cipd_bin_packages/bin" + ], + "VPYTHON_VIRTUALENV_ROOT": [ + "cache/vpython" + ] + }, + "execution_timeout_ns": 14400000000000, + "expiration_ns": 72000000000000, + "extra_tags": { + "log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + }, + "io_timeout_ns": 14400000000000, + "isolate": "perf_skia_bundled.isolate", + "max_attempts": 1, + "outputs": [ + "perf" + ] + }, "Perf-Debian9-GCC-GCE-CPU-AVX2-x86-Debug-All": { "caches": [ { @@ -74195,6 +74399,204 @@ "isolate": "swarm_recipe.isolate", "service_account": "skia-external-nano-uploader@skia-swarming-bots.iam.gserviceaccount.com" }, + "Upload-Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit": { + "caches": [ + { + "name": "vpython", + "path": "cache/vpython" + } + ], + "cipd_packages": [ + { + "name": "infra/tools/luci/kitchen/${platform}", + "path": ".", + "version": "git_revision:546aae39f1fb9dce9add528e2011afa574535ecd" + }, + { + "name": "infra/tools/luci-auth/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c" + }, + { + "name": "infra/tools/luci/vpython/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:b6cdec8586c9f8d3d728b1bc0bd4331330ba66fc" + }, + { + "name": "infra/gsutil", + "path": "cipd_bin_packages", + "version": "version:4.28" + } + ], + "command": [ + "./kitchen${EXECUTABLE_SUFFIX}", + "cook", + "-checkout-dir", + "recipe_bundle", + "-mode", + "swarming", + "-luci-system-account", + "system", + "-cache-dir", + "cache", + "-temp-dir", + "tmp", + "-known-gerrit-host", + "android.googlesource.com", + "-known-gerrit-host", + "boringssl.googlesource.com", + "-known-gerrit-host", + "chromium.googlesource.com", + "-known-gerrit-host", + "dart.googlesource.com", + "-known-gerrit-host", + "fuchsia.googlesource.com", + "-known-gerrit-host", + "go.googlesource.com", + "-known-gerrit-host", + "llvm.googlesource.com", + "-known-gerrit-host", + "skia.googlesource.com", + "-known-gerrit-host", + "webrtc.googlesource.com", + "-output-result-json", + "${ISOLATED_OUTDIR}/build_result_filename", + "-workdir", + ".", + "-recipe", + "upload_nano_results", + "-properties", + "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit\",\"gs_bucket\":\"skia-perf\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\"}", + "-logdog-annotation-url", + "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + ], + "dependencies": [ + "Housekeeper-PerCommit-BundleRecipes", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-asmjs-Release-All-PathKit" + ], + "dimensions": [ + "cpu:x86-64-Haswell_GCE", + "gpu:none", + "machine_type:n1-highmem-2", + "os:Debian-9.4", + "pool:Skia" + ], + "env_prefixes": { + "PATH": [ + "cipd_bin_packages", + "cipd_bin_packages/bin" + ], + "VPYTHON_VIRTUALENV_ROOT": [ + "cache/vpython" + ] + }, + "execution_timeout_ns": 3600000000000, + "extra_tags": { + "log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + }, + "io_timeout_ns": 3600000000000, + "isolate": "swarm_recipe.isolate", + "service_account": "skia-external-nano-uploader@skia-swarming-bots.iam.gserviceaccount.com" + }, + "Upload-Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit": { + "caches": [ + { + "name": "vpython", + "path": "cache/vpython" + } + ], + "cipd_packages": [ + { + "name": "infra/tools/luci/kitchen/${platform}", + "path": ".", + "version": "git_revision:546aae39f1fb9dce9add528e2011afa574535ecd" + }, + { + "name": "infra/tools/luci-auth/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:e1abc57be62d198b5c2f487bfb2fa2d2eb0e867c" + }, + { + "name": "infra/tools/luci/vpython/${platform}", + "path": "cipd_bin_packages", + "version": "git_revision:b6cdec8586c9f8d3d728b1bc0bd4331330ba66fc" + }, + { + "name": "infra/gsutil", + "path": "cipd_bin_packages", + "version": "version:4.28" + } + ], + "command": [ + "./kitchen${EXECUTABLE_SUFFIX}", + "cook", + "-checkout-dir", + "recipe_bundle", + "-mode", + "swarming", + "-luci-system-account", + "system", + "-cache-dir", + "cache", + "-temp-dir", + "tmp", + "-known-gerrit-host", + "android.googlesource.com", + "-known-gerrit-host", + "boringssl.googlesource.com", + "-known-gerrit-host", + "chromium.googlesource.com", + "-known-gerrit-host", + "dart.googlesource.com", + "-known-gerrit-host", + "fuchsia.googlesource.com", + "-known-gerrit-host", + "go.googlesource.com", + "-known-gerrit-host", + "llvm.googlesource.com", + "-known-gerrit-host", + "skia.googlesource.com", + "-known-gerrit-host", + "webrtc.googlesource.com", + "-output-result-json", + "${ISOLATED_OUTDIR}/build_result_filename", + "-workdir", + ".", + "-recipe", + "upload_nano_results", + "-properties", + "{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit\",\"gs_bucket\":\"skia-perf\",\"patch_issue\":\"<(ISSUE)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\"}", + "-logdog-annotation-url", + "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + ], + "dependencies": [ + "Housekeeper-PerCommit-BundleRecipes", + "Perf-Debian9-EMCC-GCE-CPU-AVX2-wasm-Release-All-PathKit" + ], + "dimensions": [ + "cpu:x86-64-Haswell_GCE", + "gpu:none", + "machine_type:n1-highmem-2", + "os:Debian-9.4", + "pool:Skia" + ], + "env_prefixes": { + "PATH": [ + "cipd_bin_packages", + "cipd_bin_packages/bin" + ], + "VPYTHON_VIRTUALENV_ROOT": [ + "cache/vpython" + ] + }, + "execution_timeout_ns": 3600000000000, + "extra_tags": { + "log_location": "logdog://logs.chromium.org/skia/<(TASK_ID)/+/annotations" + }, + "io_timeout_ns": 3600000000000, + "isolate": "swarm_recipe.isolate", + "service_account": "skia-external-nano-uploader@skia-swarming-bots.iam.gserviceaccount.com" + }, "Upload-Perf-Mac-Clang-MacBook10.1-GPU-IntelHD615-x86_64-Release-All": { "caches": [ { diff --git a/infra/pathkit/Makefile b/infra/pathkit/Makefile index 56e23e916c..eea36a0dd9 100644 --- a/infra/pathkit/Makefile +++ b/infra/pathkit/Makefile @@ -1,8 +1,27 @@ -gold-docker-image: aggregator +gold_docker_image: aggregator # Set the build context to the current work dir, so we can copy # the built binary to where we need it. docker build -t gold-karma-chrome-tests -f ./docker/gold-karma-chrome-tests/Dockerfile . +perf_docker_image: aggregator + # Set the build context to the current work dir, so we can copy + # the built binary to where we need it. + docker build -t perf-karma-chrome-tests -f ./docker/perf-karma-chrome-tests/Dockerfile . + aggregator: mkdir -p ./tmp - CGO_ENABLED=0 GOOS=linux go build -o ./tmp/gold-aggregator -a ./gold/ \ No newline at end of file + CGO_ENABLED=0 GOOS=linux go build -o ./tmp/gold-aggregator -a ./gold/ + mkdir -p ./tmp + CGO_ENABLED=0 GOOS=linux go build -o ./tmp/perf-aggregator -a ./perf/ + +# Can check CHROME_VERSION with +# docker run karma-chrome-tests /usr/bin/google-chrome-stable --version +CHROME_VERSION=68.0.3440.106_v5 + +publish_gold_karma_chrome_tests: gold_docker_image + docker tag gold-karma-chrome-tests gcr.io/skia-public/gold-karma-chrome-tests:${CHROME_VERSION} + docker push gcr.io/skia-public/gold-karma-chrome-tests:${CHROME_VERSION} + +publish_perf_karma_chrome_tests: perf_docker_image + docker tag perf-karma-chrome-tests gcr.io/skia-public/perf-karma-chrome-tests:${CHROME_VERSION} + docker push gcr.io/skia-public/perf-karma-chrome-tests:${CHROME_VERSION} \ No newline at end of file diff --git a/infra/pathkit/docker/Makefile b/infra/pathkit/docker/Makefile new file mode 100644 index 0000000000..f9be8103a5 --- /dev/null +++ b/infra/pathkit/docker/Makefile @@ -0,0 +1,16 @@ +# TODO(kjlubick) add _v1 to this version to be like the others. +EMSDK_VERSION=1.38.6_jre + +# Can check CHROME_VERSION with +# docker run karma-chrome-tests /usr/bin/google-chrome-stable --version +CHROME_VERSION=68.0.3440.106_v5 + +publish_emsdk_base: + docker build -t emsdk-base ./emsdk-base/ + docker tag emsdk-base gcr.io/skia-public/emsdk-release:${EMSDK_VERSION} + docker push gcr.io/skia-public/emsdk-release:${EMSDK_VERSION} + +publish_karma_chrome_tests: + docker build -t karma-chrome-tests ./karma-chrome-tests/ + docker tag karma-chrome-tests gcr.io/skia-public/karma-chrome-tests:${CHROME_VERSION} + docker push gcr.io/skia-public/karma-chrome-tests:${CHROME_VERSION} \ No newline at end of file diff --git a/infra/pathkit/docker/README.md b/infra/pathkit/docker/README.md index 1fb2f977a1..e4f4acc96d 100644 --- a/infra/pathkit/docker/README.md +++ b/infra/pathkit/docker/README.md @@ -15,10 +15,7 @@ it Skia-exclusive. It gets manually pushed anytime there's an update to the Dockerfile or relevant installed libraries. - docker build -t emsdk-base ./emsdk-base/ - EMSDK_VERSION="1.38.6_jre" - docker tag emsdk-base gcr.io/skia-public/emsdk-release:$EMSDK_VERSION - docker push gcr.io/skia-public/emsdk-release:$EMSDK_VERSION + make publish_emsdk_base For testing the image locally, the following flow can be helpful: @@ -40,12 +37,7 @@ it Skia-exclusive. It gets manually pushed anytime there's an update to the Dockerfile or relevant installed libraries. - docker build -t karma-chrome-tests ./karma-chrome-tests/ - # check the version of chrome with the following: - docker run karma-chrome-tests /usr/bin/google-chrome-stable --version - CHROME_VERSION="68.0.3440.106_v5" # use v1, v2, etc for any re-spins of the container. - docker tag karma-chrome-tests gcr.io/skia-public/karma-chrome-tests:$CHROME_VERSION - docker push gcr.io/skia-public/karma-chrome-tests:$CHROME_VERSION + make publish_karma_chrome_tests Of note, some versions (generally before Chrome 60) run out of space on /dev/shm when using the default Docker settings. To be safe, it is recommended to run the container @@ -72,12 +64,7 @@ It gets manually pushed anytime there's an update to the Dockerfile or the paren image (karma-chrome-tests). # Run the following from $SKIA_ROOT/infra/pathkit - make gold-docker-image - # check the version of chrome with the following: - docker run gold-karma-chrome-tests /usr/bin/google-chrome-stable --version - CHROME_VERSION="68.0.3440.106_v5" # use v1, v2, etc for any re-spins of the container. - docker tag gold-karma-chrome-tests gcr.io/skia-public/gold-karma-chrome-tests:$CHROME_VERSION - docker push gcr.io/skia-public/gold-karma-chrome-tests:$CHROME_VERSION + make publish_gold_karma_chrome_tests Of note, some versions (generally before Chrome 60) run out of space on /dev/shm when using the default Docker settings. To be safe, it is recommended to run the container @@ -92,3 +79,32 @@ For testing the image locally, the following can be helpful: # Run the tests and collect Gold output with the local source repo mkdir -p -m 0777 /tmp/dockergold docker run --shm-size=2gb -v $SKIA_ROOT:/SRC -v /tmp/dockergold:/OUT gold-karma-chrome-tests /SRC/infra/pathkit/test_pathkit.sh + +perf-karma-chrome-tests +------------------ + +This image has Google Chrome and karma/jasmine installed on it, which can +be used to run JS tests. + +This image assumes the runner wants to collect the output images and JSON data +specific to Skia Infra's Perf tool. + +It gets manually pushed anytime there's an update to the Dockerfile or the parent +image (karma-chrome-tests). + + # Run the following from $SKIA_ROOT/infra/pathkit + make publish_perf_karma_chrome_tests + +Of note, some versions (generally before Chrome 60) run out of space on /dev/shm when +using the default Docker settings. To be safe, it is recommended to run the container +with the flag --shm-size=2gb. + +For testing the image locally, the following can be helpful: + + # Run the following from $SKIA_ROOT/infra/pathkit + make perf-docker-image + # Run bash in it to poke around and make sure things are properly installed + docker run -it --shm-size=2gb perf-karma-chrome-tests /bin/bash + # Run the tests and collect Perf output with the local source repo + mkdir -p -m 0777 /tmp/dockerperf + docker run --shm-size=2gb -v $SKIA_ROOT:/SRC -v /tmp/dockerperf:/OUT perf-karma-chrome-tests /SRC/infra/pathkit/perf_pathkit.sh diff --git a/infra/pathkit/docker/perf-karma-chrome-tests/Dockerfile b/infra/pathkit/docker/perf-karma-chrome-tests/Dockerfile new file mode 100644 index 0000000000..f47a95a3ca --- /dev/null +++ b/infra/pathkit/docker/perf-karma-chrome-tests/Dockerfile @@ -0,0 +1,9 @@ +# Docker container with Chrome, and karma/jasmine, to be used to run JS tests and +# collect output for Skia Infra's Perf tool. +# +# Tests will be run as non-root (user skia, in fact), so /OUT should have permissions +# 777 so as to be able to create output there. + +FROM gcr.io/skia-public/karma-chrome-tests:68.0.3440.106_v5 + +COPY /tmp/perf-aggregator /opt/perf-aggregator \ No newline at end of file diff --git a/infra/pathkit/perf/pathkit_perf_aggregator.go b/infra/pathkit/perf/pathkit_perf_aggregator.go new file mode 100644 index 0000000000..4793ab5a8f --- /dev/null +++ b/infra/pathkit/perf/pathkit_perf_aggregator.go @@ -0,0 +1,200 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package main + +// This server runs along side the karma tests and listens for POST requests +// when any test case reports it has output for Perf. See perfReporter.js +// for the browser side part. + +// Unlike the gold ingester, the perf ingester allows multiple reports +// of the same benchmark and will output the average of these results +// on a call to dump + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "path" + "strconv" + + "github.com/google/uuid" + "go.skia.org/infra/perf/go/ingestcommon" +) + +// upload_nano_results looks for anything*.json +// We add the random UUID to avoid name clashes when uploading to +// the perf bucket (which uploads to folders based on Month/Day/Hour, which can +// easily have duplication if multiple perf tasks run in an hour.) +var JSON_FILENAME = fmt.Sprintf("%s_browser_bench.json", uuid.New().String()) + +var ( + outDir = flag.String("out_dir", "/OUT/", "location to dump the Perf JSON") + port = flag.String("port", "8081", "Port to listen on.") + + botId = flag.String("bot_id", "", "swarming bot id") + browser = flag.String("browser", "Chrome", "Browser Key") + buildBucketID = flag.Int64("buildbucket_build_id", 0, "Buildbucket build id key") + builder = flag.String("builder", "", "Builder, like 'Test-Debian9-EMCC-GCE-CPU-AVX2-wasm-Debug-All-PathKit'") + compiledLanguage = flag.String("compiled_language", "wasm", "wasm or asm.js") + config = flag.String("config", "Release", "Configuration (e.g. Debug/Release) key") + gitHash = flag.String("git_hash", "-", "The git commit hash of the version being tested") + hostOS = flag.String("host_os", "Debian9", "OS Key") + issue = flag.Int64("issue", 0, "issue (if tryjob)") + patch_storage = flag.String("patch_storage", "", "patch storage (if tryjob)") + patchset = flag.Int64("patchset", 0, "patchset (if tryjob)") + taskId = flag.String("task_id", "", "swarming task id") +) + +// Received from the JS side. +type reportBody struct { + // a name describing the benchmark. Should be unique enough to allow use of grep. + BenchName string `json:"bench_name"` + // The number of microseconds of the task. + TimeMicroSeconds float64 `json:"time_us"` +} + +// The keys to be used at the top level for all Results. +var defaultKeys map[string]string + +// contains all the results reported in through report_perf_data +var results map[string][]reportBody + +type BenchData struct { + Hash string `json:"gitHash"` + Issue string `json:"issue"` + PatchSet string `json:"patchset"` + Key map[string]string `json:"key"` + Options map[string]string `json:"options,omitempty"` + Results map[string]ingestcommon.BenchResults `json:"results"` + PatchStorage string `json:"patch_storage,omitempty"` + + SwarmingTaskID string `json:"swarming_task_id,omitempty"` + SwarmingBotID string `json:"swarming_bot_id,omitempty"` +} + +func main() { + flag.Parse() + + defaultKeys = map[string]string{ + "arch": "WASM", + "browser": *browser, + "compiled_language": *compiledLanguage, + "compiler": "emsdk", + "configuration": *config, + "cpu_or_gpu": "CPU", + "cpu_or_gpu_value": "Browser", + "os": *hostOS, + "source_type": "pathkit", + } + + results = make(map[string][]reportBody) + + http.HandleFunc("/report_perf_data", reporter) + http.HandleFunc("/dump_json", dumpJSON) + + fmt.Printf("Waiting for perf ingestion on port %s\n", *port) + + log.Fatal(http.ListenAndServe(":"+*port, nil)) +} + +// reporter handles when the client reports a test has a benchmark. +func reporter(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Only POST accepted", 400) + return + } + defer r.Body.Close() + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + http.Error(w, "Malformed body", 400) + return + } + + benchOutput := reportBody{} + if err := json.Unmarshal(body, &benchOutput); err != nil { + fmt.Println(err) + http.Error(w, "Could not unmarshal JSON", 400) + return + } + + if _, err := w.Write([]byte("Accepted")); err != nil { + fmt.Printf("Could not write response: %s\n", err) + return + } + + results[benchOutput.BenchName] = append(results[benchOutput.BenchName], benchOutput) +} + +// createOutputFile creates a file and set permissions correctly. +func createOutputFile(p string) (*os.File, error) { + outputFile, err := os.Create(p) + if err != nil { + return nil, fmt.Errorf("Could not open file %s on disk: %s", p, err) + } + // Make this accessible (and deletable) by all users + if err = outputFile.Chmod(0666); err != nil { + return nil, fmt.Errorf("Could not change permissions of file %s: %s", p, err) + } + return outputFile, nil +} + +// dumpJSON writes out a JSON file with all the results, typically at the end of +// all the tests. If there is more than one result per benchmark, we report the average. +func dumpJSON(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Only POST accepted", 400) + return + } + + p := path.Join(*outDir, JSON_FILENAME) + outputFile, err := createOutputFile(p) + defer outputFile.Close() + if err != nil { + fmt.Println(err) + http.Error(w, "Could not open json file on disk", 500) + return + } + + benchData := BenchData{ + Hash: *gitHash, + Issue: strconv.FormatInt(*issue, 10), + PatchStorage: *patch_storage, + PatchSet: strconv.FormatInt(*patchset, 10), + Key: defaultKeys, + SwarmingBotID: *botId, + SwarmingTaskID: *taskId, + } + + allResults := make(map[string]ingestcommon.BenchResults) + for name, benches := range results { + samples := []float64{} + total := float64(0) + for _, t := range benches { + samples = append(samples, t.TimeMicroSeconds) + total += t.TimeMicroSeconds + } + allResults[name] = map[string]ingestcommon.BenchResult{ + "default": map[string]interface{}{ + "average_us": total / float64(len(benches)), + "samples": samples, + }, + } + } + benchData.Results = allResults + + enc := json.NewEncoder(outputFile) + enc.SetIndent("", " ") // Make it human readable. + if err := enc.Encode(&benchData); err != nil { + fmt.Println(err) + http.Error(w, "Could not write json to disk", 500) + return + } + fmt.Println("JSON Written") +} diff --git a/infra/pathkit/perf_pathkit.sh b/infra/pathkit/perf_pathkit.sh new file mode 100755 index 0000000000..55ab29d8b8 --- /dev/null +++ b/infra/pathkit/perf_pathkit.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2018 Google LLC +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This assumes it is being run inside a docker container of perf-karma-chrome-tests +# and a Skia checkout has been mounted at /SRC and the output directory +# is mounted at /OUT + +# For example: +# docker run -v $SKIA_ROOT:/SRC -v /tmp/dockerout:/OUT gcr.io/skia-public/perf-karma-chrome-tests:68.0.3440.106_v1 /SRC/infra/pathkit/perf_pathkit.sh + +set -ex + +#BASE_DIR is the dir this script is in ($SKIA_ROOT/infra/pathkit) +BASE_DIR=`cd $(dirname ${BASH_SOURCE[0]}) && pwd` +PATHKIT_DIR=$BASE_DIR/../../modules/pathkit + +# Start the aggregator in the background +/opt/perf-aggregator $@ & +# Run the tests 10 times to get a wide set of data +for i in `seq 1 10`; +do + npx karma start $PATHKIT_DIR/karma.bench.conf.js --single-run +done +# Tell the aggregator to dump the json +# This curl command gets the HTTP code and stores it into $CODE +CODE=`curl -s -o /dev/null -I -w "%{http_code}" -X POST localhost:8081/dump_json` +if [ $CODE -ne 200 ]; then + # If we don't get 200 back, something is wrong with writing to disk, so exit with error + exit 1 +fi diff --git a/modules/pathkit/externs.js b/modules/pathkit/externs.js index c6c5fc902c..e5b603613d 100644 --- a/modules/pathkit/externs.js +++ b/modules/pathkit/externs.js @@ -23,6 +23,7 @@ var PathKit = { SkBits2FloatUnsigned: function(num) {}, _malloc: function(size) {}, + _free: function(ptr) {}, onRuntimeInitialized: function() {}, _FromCmds: function(ptr, size) {}, loadCmdsTypedArray: function(arr) {}, @@ -31,6 +32,9 @@ var PathKit = { cubicYFromX: function(cpx1, cpy1, cpx2, cpy2, X) {}, cubicPtFromT: function(cpx1, cpy1, cpx2, cpy2, T) {}, + /** + * @type {Float32Array} + */ HEAPF32: {}, SkPath: { diff --git a/modules/pathkit/helper.js b/modules/pathkit/helper.js index 51e1ffd7cc..82713ba592 100644 --- a/modules/pathkit/helper.js +++ b/modules/pathkit/helper.js @@ -63,7 +63,10 @@ // See above for example of cmds. PathKit.FromCmds = function(cmds) { var ptrLen = PathKit.loadCmdsTypedArray(cmds); - return PathKit._FromCmds(ptrLen[0], ptrLen[1]); + var path = PathKit._FromCmds(ptrLen[0], ptrLen[1]); + // TODO(kjlubick): cache this memory blob somehow. + PathKit._free(ptrLen[0]); + return path; } /** diff --git a/modules/pathkit/karma.bench.conf.js b/modules/pathkit/karma.bench.conf.js new file mode 100644 index 0000000000..a2808a60b8 --- /dev/null +++ b/modules/pathkit/karma.bench.conf.js @@ -0,0 +1,88 @@ +const isDocker = require('is-docker')(); + +module.exports = function(config) { + // Set the default values to be what are needed when testing the + // WebAssembly build locally. + let cfg = { + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + // list of files / patterns to load in the browser + files: [ + { pattern: 'npm-wasm/bin/pathkit.wasm', included:false, served:true}, + 'perf/perfReporter.js', + 'npm-wasm/bin/pathkit.js', + 'perf/*.bench.js' + ], + + proxies: { + '/pathkit/': '/base/npm-wasm/bin/' + }, + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['dots'], + + // web server port + port: 4444, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + browserDisconnectTimeout: 10000, + browserNoActivityTimeout: 10000, + + // start these browsers + browsers: ['Chrome'], + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity, + }; + + if (isDocker) { + // See https://hackernoon.com/running-karma-tests-with-headless-chrome-inside-docker-ae4aceb06ed3 + cfg.browsers = ['ChromeHeadlessNoSandbox'], + cfg.customLaunchers = { + ChromeHeadlessNoSandbox: { + base: 'ChromeHeadless', + flags: [ + // Without this flag, we see an error: + // Failed to move to new namespace: PID namespaces supported, Network namespace supported, but failed: errno = Operation not permitted + '--no-sandbox' + ], + }, + }; + } + + if (process.env.ASM_JS) { + console.log('asm.js is under test'); + cfg.files = [ + { pattern: 'npm-asmjs/bin/pathkit.js.mem', included:false, served:true}, + 'perf/perfReporter.js', + 'npm-asmjs/bin/pathkit.js', + 'perf/*.bench.js' + ]; + + cfg.proxies = { + '/pathkit/': '/base/npm-asmjs/bin/' + }; + } else { + console.log('wasm is under test'); + } + + config.set(cfg); +} diff --git a/modules/pathkit/karma.conf.js b/modules/pathkit/karma.conf.js index faa870ef8e..649d21d0ef 100644 --- a/modules/pathkit/karma.conf.js +++ b/modules/pathkit/karma.conf.js @@ -18,7 +18,7 @@ module.exports = function(config) { ], proxies: { - "/pathkit/": "/base/npm-wasm/bin/test/" + '/pathkit/': '/base/npm-wasm/bin/test/' }, // test results reporter to use @@ -80,7 +80,7 @@ module.exports = function(config) { ]; cfg.proxies = { - "/pathkit/": "/base/npm-asmjs/bin/test/" + '/pathkit/': '/base/npm-asmjs/bin/test/' }; } else { console.log('wasm is under test'); diff --git a/modules/pathkit/npm-asmjs/package.json b/modules/pathkit/npm-asmjs/package.json index 701e3070ea..306c543031 100644 --- a/modules/pathkit/npm-asmjs/package.json +++ b/modules/pathkit/npm-asmjs/package.json @@ -1,6 +1,6 @@ { "name": "pathkit-asmjs", - "version": "0.4.1", + "version": "0.4.2", "description": "A asm.js version of Skia's PathOps toolkit", "main": "bin/pathkit.js", "homepage": "https://github.com/google/skia/tree/master/modules/pathkit", diff --git a/modules/pathkit/npm-wasm/package.json b/modules/pathkit/npm-wasm/package.json index 80cbaec6b6..a18e61380e 100644 --- a/modules/pathkit/npm-wasm/package.json +++ b/modules/pathkit/npm-wasm/package.json @@ -1,6 +1,6 @@ { "name": "pathkit-wasm", - "version": "0.4.1", + "version": "0.4.2", "description": "A WASM version of Skia's PathOps toolkit", "main": "bin/pathkit.js", "homepage": "https://github.com/google/skia/tree/master/modules/pathkit", diff --git a/modules/pathkit/perf/effects.bench.js b/modules/pathkit/perf/effects.bench.js new file mode 100644 index 0000000000..d1be9ec862 --- /dev/null +++ b/modules/pathkit/perf/effects.bench.js @@ -0,0 +1,143 @@ + + +describe('PathKit\'s Effects', function() { + // Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up. + var PathKit = null; + const LoadPathKit = new Promise(function(resolve, reject) { + if (PathKit) { + resolve(); + } else { + PathKitInit({ + locateFile: (file) => '/pathkit/'+file, + }).then((_PathKit) => { + PathKit = _PathKit; + resolve(); + }); + } + }); + + // see https://fiddle.skia.org/c/@discrete_path + function drawStar(X=128, Y=128, R=116) { + let p = PathKit.NewPath(); + p.moveTo(X + R, Y); + for (let i = 1; i < 8; i++) { + let a = 2.6927937 * i; + p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a)); + } + p.closePath(); + return p; + } + + it('effects_dash', function(done) { + function setup(ctx) { + ctx.path = drawStar(); + } + + function test(ctx) { + let path = ctx.path.copy().dash(10, 3, 1); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('effects_dash', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('effects_trim', function(done) { + function setup(ctx) { + ctx.path = drawStar(); + } + + function test(ctx) { + let path = ctx.path.copy().trim(0.25, .8); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('effects_trim', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('effects_trim_complement', function(done) { + function setup(ctx) { + ctx.path = drawStar(); + } + + function test(ctx) { + let path = ctx.path.copy().trim(0.25, .8, true); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('effects_trim_complement', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('effects_transform', function(done) { + function setup(ctx) { + ctx.path = drawStar(); + } + + function test(ctx) { + let path = ctx.path.copy().transform(3, 0, 0, + 0, 3, 0, + 0, 0, 1); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('effects_transform', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('effects_stroke', function(done) { + function setup(ctx) { + ctx.path = drawStar(); + } + + function test(ctx) { + let path = ctx.path.copy().stroke({ + width: 15, + join: PathKit.StrokeJoin.BEVEL, + cap: PathKit.StrokeCap.BUTT, + miter_limit: 2, + }); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('effects_stroke', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + +}); \ No newline at end of file diff --git a/modules/pathkit/perf/path.bench.js b/modules/pathkit/perf/path.bench.js new file mode 100644 index 0000000000..35d8b252f7 --- /dev/null +++ b/modules/pathkit/perf/path.bench.js @@ -0,0 +1,313 @@ + + +describe('PathKit\'s Path Behavior', function() { + // Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up. + var PathKit = null; + const LoadPathKit = new Promise(function(resolve, reject) { + if (PathKit) { + resolve(); + } else { + PathKitInit({ + locateFile: (file) => '/pathkit/'+file, + }).then((_PathKit) => { + PathKit = _PathKit; + resolve(); + }); + } + }); + + function drawPath() { + let path = PathKit.NewPath(); + path.moveTo(20, 5); + path.lineTo(30, 20); + path.lineTo(40, 10); + path.lineTo(50, 20); + path.lineTo(60, 0); + path.lineTo(20, 5); + + path.moveTo(20, 80); + path.bezierCurveTo(90, 10, 160, 150, 190, 10); + + path.moveTo(36, 148); + path.quadraticCurveTo(66, 188, 120, 136); + path.lineTo(36, 148); + + path.rect(5, 170, 20, 20); + + path.moveTo(150, 180); + path.arcTo(150, 100, 50, 200, 20); + path.lineTo(160, 160); + + path.moveTo(20, 120); + path.arc(20, 120, 18, 0, 1.75 * Math.PI); + path.lineTo(20, 120); + + let secondPath = PathKit.NewPath(); + secondPath.ellipse(130, 25, 30, 10, -1*Math.PI/8, Math.PI/6, 1.5*Math.PI, false); + + path.addPath(secondPath); + + let m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix(); + m.a = 1; m.b = 0; + m.c = 0; m.d = 1; + m.e = 0; m.f = 20.5; + + path.addPath(secondPath, m); + secondPath.delete(); + return path; + } + + it('path_path2dapi', function(done) { + function setup(ctx) { } + + function test(ctx) { + path = drawPath(); + path.delete(); + } + + function teardown(ctx) { } + + LoadPathKit.then(() => { + benchmarkAndReport('path_path2dapi', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + describe('import options', function() { + it('path_copy', function(done) { + function setup(ctx) { + ctx.path = PathKit.FromSVGString('M 205,5 L 795,5 L 595,295 L 5,295 L 205,5 z'); + } + + function test(ctx) { + let p = ctx.path.copy(); + p.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_copy', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_from_api_calls', function(done) { + function setup(ctx) { } + + function test(ctx) { + let p = PathKit.NewPath() + .moveTo(205, 5) + .lineTo(795, 5) + .lineTo(595, 295) + .lineTo(5, 295) + .lineTo(205, 5) + .close(); + p.delete(); + } + + function teardown(ctx) { } + + LoadPathKit.then(() => { + benchmarkAndReport('path_from_api_calls', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_fromCmds', function(done) { + function setup(ctx) { } + + function test(ctx) { + let p = PathKit.FromCmds( + [[PathKit.MOVE_VERB, 205, 5], + [PathKit.LINE_VERB, 795, 5], + [PathKit.LINE_VERB, 595, 295], + [PathKit.LINE_VERB, 5, 295], + [PathKit.LINE_VERB, 205, 5], + [PathKit.CLOSE_VERB]]); + p.delete(); + } + + function teardown(ctx) { } + + LoadPathKit.then(() => { + benchmarkAndReport('path_fromCmds', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_fromSVGString', function(done) { + function setup(ctx) {} + + function test(ctx) { + // https://upload.wikimedia.org/wikipedia/commons/e/e7/Simple_parallelogram.svg + let p = PathKit.FromSVGString('M 205,5 L 795,5 L 595,295 L 5,295 L 205,5 z'); + p.delete(); + } + + function teardown(ctx) { } + + LoadPathKit.then(() => { + benchmarkAndReport('path_fromSVGString', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + }); + + describe('export options', function() { + it('path_toCmds', function(done) { + function setup(ctx) { + ctx.path = drawPath(); + } + + function test(ctx) { + ctx.path.toCmds(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_toCmds', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_toPath2D', function(done) { + function setup(ctx) { + ctx.path = drawPath(); + } + + function test(ctx) { + ctx.path.toPath2D(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_toPath2D', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_toSVGString', function(done) { + function setup(ctx) { + ctx.path = drawPath(); + } + + function test(ctx) { + ctx.path.toSVGString(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_toSVGString', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + }); + + describe('matrix options', function() { + function drawTriangle() { + let path = PathKit.NewPath(); + path.moveTo(0, 0); + path.lineTo(10, 0); + path.lineTo(10, 10); + path.close(); + return path; + } + + it('path_add_path_svgmatrix', function(done) { + function setup(ctx) { + ctx.path = drawTriangle(); + } + + function test(ctx) { + let path = PathKit.NewPath(); + let m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix(); + m.a = 1; m.b = 0; + m.c = 0; m.d = 1; + m.e = 0; m.f = 20.5; + path.addPath(ctx.path, m); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_add_path_svgmatrix', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_add_path_svgmatrix_reuse', function(done) { + function setup(ctx) { + ctx.path = drawTriangle(); + let m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix(); + ctx.matrix = m; + } + + function test(ctx) { + let path = PathKit.NewPath(); + let m = ctx.matrix + m.a = 1; m.b = 0; + m.c = 0; m.d = 1; + m.e = 0; m.f = 20.5; + path.addPath(ctx.path, m); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_add_path_svgmatrix_reuse', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('path_add_path_svgmatrix_bare', function(done) { + function setup(ctx) { + ctx.path = drawTriangle(); + } + + function test(ctx) { + let path = PathKit.NewPath(); + path.addPath(ctx.path, 1, 0, 0, 1, 0, 20.5); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('path_add_path_svgmatrix_bare', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + }); + +}); \ No newline at end of file diff --git a/modules/pathkit/perf/pathops.bench.js b/modules/pathkit/perf/pathops.bench.js new file mode 100644 index 0000000000..2da6553850 --- /dev/null +++ b/modules/pathkit/perf/pathops.bench.js @@ -0,0 +1,172 @@ + + +describe('PathKit\'s Pathops', function() { + // Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up. + var PathKit = null; + const LoadPathKit = new Promise(function(resolve, reject) { + if (PathKit) { + resolve(); + } else { + PathKitInit({ + locateFile: (file) => '/pathkit/'+file, + }).then((_PathKit) => { + PathKit = _PathKit; + resolve(); + }); + } + }); + + // see https://fiddle.skia.org/c/@discrete_path + function drawStar(X=128, Y=128, R=116) { + let p = PathKit.NewPath(); + p.moveTo(X + R, Y); + for (let i = 1; i < 8; i++) { + let a = 2.6927937 * i; + p.lineTo(X + R * Math.cos(a), Y + R * Math.sin(a)); + } + p.closePath(); + return p; + } + + it('pathops_simplify', function(done) { + function setup(ctx) { + ctx.path = drawStar(); + } + + function test(ctx) { + let path = ctx.path.copy().simplify(); + path.delete(); + } + + function teardown(ctx) { + ctx.path.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('pathops_simplify', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('pathops_diff', function(done) { + function setup(ctx) { + // Values chosen abitrarily to have some overlap and some not. + ctx.path1 = drawStar(X=120, Y=120); + ctx.path2 = drawStar(X=140, Y=145); + } + + function test(ctx) { + let path = PathKit.MakeFromOp(ctx.path1, ctx.path2, PathKit.PathOp.DIFFERENCE); + path.delete(); + } + + function teardown(ctx) { + ctx.path1.delete(); + ctx.path2.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('pathops_diff', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('pathops_intersect', function(done) { + function setup(ctx) { + // Values chosen abitrarily to have some overlap and some not. + ctx.path1 = drawStar(X=120, Y=120); + ctx.path2 = drawStar(X=140, Y=145); + } + + function test(ctx) { + let path = PathKit.MakeFromOp(ctx.path1, ctx.path2, PathKit.PathOp.INTERSECT); + path.delete(); + } + + function teardown(ctx) { + ctx.path1.delete(); + ctx.path2.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('pathops_intersect', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('pathops_union', function(done) { + function setup(ctx) { + // Values chosen abitrarily to have some overlap and some not. + ctx.path1 = drawStar(X=120, Y=120); + ctx.path2 = drawStar(X=140, Y=145); + } + + function test(ctx) { + let path = PathKit.MakeFromOp(ctx.path1, ctx.path2, PathKit.PathOp.UNION); + path.delete(); + } + + function teardown(ctx) { + ctx.path1.delete(); + ctx.path2.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('pathops_union', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('pathops_xor', function(done) { + function setup(ctx) { + // Values chosen abitrarily to have some overlap and some not. + ctx.path1 = drawStar(X=120, Y=120); + ctx.path2 = drawStar(X=140, Y=145); + } + + function test(ctx) { + let path = PathKit.MakeFromOp(ctx.path1, ctx.path2, PathKit.PathOp.XOR); + path.delete(); + } + + function teardown(ctx) { + ctx.path1.delete(); + ctx.path2.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('pathops_xor', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + + it('pathops_reverse_diff', function(done) { + function setup(ctx) { + // Values chosen abitrarily to have some overlap and some not. + ctx.path1 = drawStar(X=120, Y=120); + ctx.path2 = drawStar(X=140, Y=145); + } + + function test(ctx) { + let path = PathKit.MakeFromOp(ctx.path1, ctx.path2, PathKit.PathOp.REVERSE_DIFFERENCE); + path.delete(); + } + + function teardown(ctx) { + ctx.path1.delete(); + ctx.path2.delete(); + } + + LoadPathKit.then(() => { + benchmarkAndReport('pathops_reverse_diff', setup, test, teardown).then(() => { + done(); + }).catch(reportError(done)); + }); + }); + +}); \ No newline at end of file diff --git a/modules/pathkit/perf/perfReporter.js b/modules/pathkit/perf/perfReporter.js new file mode 100644 index 0000000000..d74110c00e --- /dev/null +++ b/modules/pathkit/perf/perfReporter.js @@ -0,0 +1,72 @@ +const REPORT_URL = 'http://localhost:8081/report_perf_data' +// Set this to enforce that the perf server must be up. +// Typically used for debugging. +const fail_on_no_perf = false; + + +function benchmarkAndReport(benchName, setupFn, testFn, teardownFn) { + let ctx = {}; + // warmup 3 times (arbitrary choice) + setupFn(ctx); + testFn(ctx); + testFn(ctx); + testFn(ctx); + teardownFn(ctx); + + ctx = {}; + setupFn(ctx); + let start = Date.now(); + let now = start; + times = 0; + // See how many times we can do it in 100ms (arbitrary choice) + while (now - start < 100) { + testFn(ctx); + now = Date.now(); + times++; + } + + teardownFn(ctx); + + // Try to make it go for 2 seconds (arbitrarily chosen) + // Since the pre-try took 100ms, multiply by 20 to get + // approximate tries in 2s + let goalTimes = times * 20; + setupFn(ctx); + start = Date.now(); + times = 0; + while (times < goalTimes) { + testFn(ctx); + times++; + } + let end = Date.now(); + teardownFn(ctx); + + let us = (end - start) * 1000 / times; + console.log(benchName, `${us} microseconds`) + return _report(us, benchName); +} + + +function _report(microseconds, benchName) { + return fetch(REPORT_URL, { + method: 'POST', + mode: 'no-cors', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + 'bench_name': benchName, + 'time_us': microseconds, + }) + }).then(() => console.log(`Successfully reported ${benchName} to perf aggregator`)); +} + +function reportError(done) { + return (e) => { + console.log("Error with fetching. Likely could not connect to aggegator server", e.message); + if (fail_on_no_perf) { + expect(e).toBeUndefined(); + } + done(); + }; +} \ No newline at end of file