diff --git a/media/EdgeTPUCfgEditor/cfgeditor.css b/media/EdgeTPUCfgEditor/cfgeditor.css new file mode 100644 index 00000000..c0847989 --- /dev/null +++ b/media/EdgeTPUCfgEditor/cfgeditor.css @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +label { + white-space: pre-wrap; +} + +.maintitle { + width: 100%; + display: flex; +} + +.maintitle span { + float: left; + display: block; + padding-left: 5px; +} + +.statusbar { + width: 100%; + display: flex; + margin-top: 10px; + margin-bottom: 20px; +} + +.statusbar .detail { + box-sizing: border-box; + float: left; + background: #007acc; + color: #fff; + position: relative; + padding-left: 10px; + padding-right: 10px; + width: 70px; + height: 32px; + line-height: 32px; + text-align: center; + display: block; +} + +.statusbar .detail:after { + box-sizing: border-box; + content: ''; + border-left: 16px solid #007acc; + border-top: 16px solid transparent; + border-bottom: 16px solid transparent; + position: absolute; + top: 0; + left: 100%; + z-index: 1; +} + +.statusbar .detail .expanded { + display: inline-block; +} + +.statusbar .steps { + display: inline-flex; +} + +.statusbar .steps .step { + box-sizing: border-box; + float: left; + background: #007acc; + color: #fff; + position: relative; + padding-left: 10px; + width: 110px; + height: 32px; + line-height: 32px; + display: flex; + justify-content: center; +} + +.statusbar .steps .step span { + padding-left: 5px; +} + +.statusbar .steps .step:before { + box-sizing: border-box; + content: ''; + border-left: 16px solid #fff; + border-top: 16px solid transparent; + border-bottom: 16px solid transparent; + position: absolute; + top: 0; + left: 0; +} + +.statusbar .steps .step:after { + box-sizing: border-box; + content: ''; + border-left: 16px solid #007acc; + border-top: 16px solid transparent; + border-bottom: 16px solid transparent; + position: absolute; + top: 0; + left: 100%; + z-index: 1; +} + +.statusbar .steps .step.current { + box-sizing: border-box; + float: left; + background: #4298da; + color: #fff; + position: relative; + padding-left: 10px; + width: 110px; + height: 32px; + line-height: 32px; + display: flex; + justify-content: center; +} + +.statusbar .steps .step.current:after { + box-sizing: border-box; + content: ''; + border-left: 16px solid #4298da; + border-top: 16px solid transparent; + border-bottom: 16px solid transparent; + position: absolute; + top: 0; + left: 100%; + z-index: 1; +} + +.statusbar .steps .step .title { + cursor: pointer; +} + +.optionPanel { + display: flex; +} + +.optionPanel .options { + display: none; +} + +#optionImport .basic, +#optionImport .advanced, +#optionQuantize .basic, +#optionQuantize .advanced { + display: none; +} + +.optionPanel .options .prerequisite .title, +.optionPanel .options .basic .title, +.optionPanel .options .advanced .title { + font-weight: bold; + font-size: 15px; + margin-bottom: 15px; + margin-top: 15px; +} + +.optionPanel .options .prerequisite .option, +.optionPanel .options .basic .option, +.optionPanel .options .advanced .option { + margin-bottom: 5px; +} + +.codicon.codicon-question .help { + visibility: hidden; + width: auto; + background-color: var(--vscode-editorSuggestWidget-background); + color: var(--vscode-editorSuggestWidget-foreground); + border: 2px solid var(--vscode-editorSuggestWidget-border); + font-size: small; + text-align: left; + position: absolute; + z-index: 1; + margin-left: 10px; + padding: 6px 6px 10px 8px; +} + +.codicon.codicon-question:hover .help { + visibility: visible; +} diff --git a/media/EdgeTPUCfgEditor/cfgeditor.html b/media/EdgeTPUCfgEditor/cfgeditor.html new file mode 100644 index 00000000..90be97e7 --- /dev/null +++ b/media/EdgeTPUCfgEditor/cfgeditor.html @@ -0,0 +1,132 @@ + + + + + + + + + + + + cfg editor + + +
+ + Click checkbox to enable each step. +
+
+
+
+
+ Steps +
+
+
+
+ + Compile +
+
+ + Profile +
+
+
+
+
+ +
+
+
+ +
+
+
+
+ Basic Options +
+
+ + Input Path + + +
+
+ + Output Path + + +
+
+
+
+ Advanced Options +
+
+ + Intermediate_tensors + + + + This option cannot be with 'search delegate' + + +
+
+ + Show Operations + + + + Print the log showing operations that mapped to the Edge TPU. + + +
+
+ + Search Delegate + + + + Enable repeated search for a new compilation stopping point earlier in the graph, to avoid rare compiler failures when it encounters an unsupported operation. + + +
+
+ + Delegate Search Step + + + + Specify a step size (the number of ops to move backward)
+ Default size is 1 and the mindest size is also 1. +
+
+
+
+
+
+
+
+ + diff --git a/media/EdgeTPUCfgEditor/displaycfg.js b/media/EdgeTPUCfgEditor/displaycfg.js new file mode 100644 index 00000000..f0a0cf60 --- /dev/null +++ b/media/EdgeTPUCfgEditor/displaycfg.js @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function displayCfgToEditor(cfg) { + const edgeTPUCompiler = cfg["edgetpu-compiler"]; + document.getElementById("checkboxEdgeTPUCompile").checked = cfgBoolean( + edgeTPUCompiler["edgetpu-compile"] + ); + document.getElementById("checkboxEdgeTPUProfile").checked = cfgBoolean( + edgeTPUCompiler["edgetpu-profile"] + ); + + const edgeTPUCompile = cfg["edgetpu-compile"]; + document.getElementById("EdgeTPUInputPath").value = cfgString( + edgeTPUCompile?.["input_path"] + ); + document.getElementById("EdgeTPUOutputPath").value = cfgString( + edgeTPUCompile?.["output_path"] + ); + document.getElementById("EdgeTPUIntermediateTensorsInputArrays").value = + cfgString(edgeTPUCompile?.["intermediate_tensors"]); + document.getElementById("EdgeTPUShowOperations").checked = cfgBoolean( + edgeTPUCompile?.["show_operations"] + ); + document.getElementById("EdgeTPUSearchDelegate").checked = cfgBoolean( + edgeTPUCompile?.["search_delegate"] + ); + document.getElementById("EdgeTPUDelegateSearchStep").value = cfgString( + edgeTPUCompile?.["delegate_search_step"], + "1" + ); +} + +function cfgString(str, defaultStr = "") { + if (str === null || str === undefined) { + return defaultStr; + } + return str.trim(); +} + +function cfgBoolean(str) { + if (str === null || str === undefined) { + return false; + } + + if (str === "True") { + return true; + } + + return false; +} diff --git a/media/EdgeTPUCfgEditor/index.js b/media/EdgeTPUCfgEditor/index.js new file mode 100644 index 00000000..44cad82f --- /dev/null +++ b/media/EdgeTPUCfgEditor/index.js @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { displayCfgToEditor } from "./displaycfg.js"; +import { + applyUpdates, + updateEdgeTPUStep, + updateEdgeTPUCompile, +} from "./updateContent.js"; +import { updateStepUI } from "./updateUI.js"; +import { postMessageToVsCode } from "./vscodeapi.js"; + +// Just like a regular webpage we need to wait for the webview +// DOM to load before we can reference any of the HTML elements +// or toolkit components +window.addEventListener("load", main); + +// Main function that gets executed once the webview DOM loads +function main() { + registerCompilerStep(); + registerCompileOptions(); + registerCodiconEvents(); + + // event from vscode extension + window.addEventListener("message", (event) => { + const message = event.data; + switch (message.type) { + case "displayCfgToEditor": + displayCfgToEditor(message.text); + break; + case "setDefaultEdgetpuValues": + setDefaultEdgetpuValues(message.name); + break; + case "applyDialogPath": + document.getElementById(message.elemID).value = message.path; + switch (message.step) { + case "EdgeTPUCompile": + updateEdgeTPUCompile(); + break; + default: + break; + } + applyUpdates(); + break; + default: + break; + } + }); + + postMessageToVsCode({ type: "requestDisplayCfg" }); +} + +function setDefaultEdgetpuValues(name) { + // EdgeTPu COmpiler steps + document.getElementById("checkboxEdgeTPUCompile").checked = true; + + updateEdgeTPUStep(); + + // compile step + let compiledName = name + ".tflite"; + let compiledExt = name + "_edgetpu.tflite"; + document.getElementById("EdgeTPUInputPath").value = compiledName; + document.getElementById("EdgeTPUOutputPath").value = compiledExt; + + updateEdgeTPUCompile(); + + // apply + applyUpdates(); +} + +function registerCompilerStep() { + const checkboxEdgeTPUCompile = document.getElementById( + "checkboxEdgeTPUCompile" + ); + const checkboxEdgeTPUProfile = document.getElementById( + "checkboxEdgeTPUProfile" + ); + const stepEdgeTPUCompile = document.getElementById("stepEdgeTPUCompile"); + const stepEdgeTPUProfile = document.getElementById("stepEdgeTPUProfile"); + + checkboxEdgeTPUCompile.addEventListener("click", function () { + updateEdgeTPUStep(); + applyUpdates(); + }); + checkboxEdgeTPUProfile.addEventListener("click", function () { + updateEdgeTPUStep(); + applyUpdates(); + }); + + stepEdgeTPUCompile.addEventListener("click", function () { + updateStepUI("EdgeTPUCompile"); + }); + stepEdgeTPUProfile.addEventListener("click", function () { + updateStepUI("EdgeTPUProfile"); + }); +} + +function registerCompileOptions() { + const edgeTPUInputPath = document.getElementById("EdgeTPUInputPath"); + const edgeTPUIntermediateTensors = document.getElementById( + "EdgeTPUIntermediateTensorsInputArrays" + ); + const edgeTPUShowOperations = document.getElementById( + "EdgeTPUShowOperations" + ); + const edgeTPUSearchDelegate = document.getElementById( + "EdgeTPUSearchDelegate" + ); + const edgeTPUDelegateSearchStep = document.getElementById( + "EdgeTPUDelegateSearchStep" + ); + const edgeTPUDelegateSearchStepDiv = document.getElementById( + "EdgeTPUDelegateSearchStepDiv" + ); + + edgeTPUInputPath.addEventListener("input", function () { + updateEdgeTPUCompile(); + applyUpdates(); + }); + edgeTPUIntermediateTensors.addEventListener("input", function () { + if (edgeTPUSearchDelegate.checked) { + edgeTPUSearchDelegate.checked = false; + edgeTPUDelegateSearchStepDiv.style.display = "none"; + } + updateEdgeTPUCompile(); + applyUpdates(); + }); + edgeTPUShowOperations.addEventListener("click", function () { + updateEdgeTPUCompile(); + applyUpdates(); + }); + edgeTPUSearchDelegate.addEventListener("click", function () { + if (edgeTPUSearchDelegate.checked) { + edgeTPUIntermediateTensors.value = ""; + edgeTPUDelegateSearchStepDiv.style.display = "block"; + } else { + edgeTPUDelegateSearchStepDiv.style.display = "none"; + } + updateEdgeTPUCompile(); + applyUpdates(); + }); + edgeTPUDelegateSearchStep.addEventListener("input", function () { + edgeTPUDelegateSearchStep.value = + edgeTPUDelegateSearchStep.value < 1 + ? "1" + : edgeTPUDelegateSearchStep.value; + updateEdgeTPUCompile(); + applyUpdates(); + }); +} + +function registerCodiconEvents() { + document + .getElementById("EdgeTPUInputPathSearch") + .addEventListener("click", function () { + postMessageToVsCode({ + type: "getPathByDialog", + isFolder: false, + ext: ["tflite"], + oldPath: document.getElementById("EdgeTPUInputPath").value, + postStep: "EdgeTPUCompile", + postElemID: "EdgeTPUInputPath", + }); + }); +} diff --git a/media/EdgeTPUCfgEditor/updateContent.js b/media/EdgeTPUCfgEditor/updateContent.js new file mode 100644 index 00000000..f4dee594 --- /dev/null +++ b/media/EdgeTPUCfgEditor/updateContent.js @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { postMessageToVsCode } from "./vscodeapi.js"; + +function iniKeyValueString(iniKey, iniValue, noEffectValue = undefined) { + if (iniValue === null || iniValue === undefined) { + return ""; + } + + if (iniValue === false) { + return ""; + } else if (iniValue === true) { + return iniKey + "=True\n"; + } + + const trimmedValue = iniValue.trim(); + if (trimmedValue === "" || trimmedValue === noEffectValue) { + return ""; + } + + return iniKey + "=" + trimmedValue + "\n"; +} + +export function applyUpdates() { + postMessageToVsCode({ type: "updateDocument" }); +} + +export function updateEdgeTPUStep() { + postMessageToVsCode({ + type: "setParam", + section: "edgetpu-compiler", + param: "edgetpu-compile", + value: document.getElementById("checkboxEdgeTPUCompile").checked + ? "True" + : "False", + }); + postMessageToVsCode({ + type: "setParam", + section: "edgetpu-compiler", + param: "edgetpu-profile", + value: document.getElementById("checkboxEdgeTPUProfile").checked + ? "True" + : "False", + }); +} + +function addPostfixToFileName(filePath = "", postfix = "") { + if (filePath.trim() === "") { + return ""; + } + const parts = filePath.split("."); + let newFilePath = ""; + if (parts.length < 2) { + newFilePath = `${filePath}${postfix}`; + } else { + const fileName = parts.slice(0, -1).join("."); + const fileExtension = parts[parts.length - 1]; + const newFileName = `${fileName}${postfix}`; + newFilePath = `${newFileName}.${fileExtension}`; + } + + return newFilePath; +} + +export function updateEdgeTPUCompile() { + let content = ""; + content += iniKeyValueString( + "input_path", + document.getElementById("EdgeTPUInputPath").value + ); + content += iniKeyValueString( + "output_path", + addPostfixToFileName( + document.getElementById("EdgeTPUInputPath").value, + "_edgetpu" + ) + ); + content += iniKeyValueString( + "intermediate_tensors", + document.getElementById("EdgeTPUIntermediateTensorsInputArrays").value + ); + content += iniKeyValueString( + "show_operations", + document.getElementById("EdgeTPUShowOperations").checked + ); + content += iniKeyValueString( + "search_delegate", + document.getElementById("EdgeTPUSearchDelegate").checked + ); + content += iniKeyValueString( + "delegate_search_step", + document.getElementById("EdgeTPUSearchDelegate").checked + ? document.getElementById("EdgeTPUDelegateSearchStep").value < 1 + ? "1" + : document.getElementById("EdgeTPUDelegateSearchStep").value + : undefined + ); + + postMessageToVsCode({ + type: "setSection", + section: "edgetpu-compile", + param: content, + }); +} + +export function updateEdgeTPUProfile() { + let content = ""; + + postMessageToVsCode({ + type: "setSection", + section: "edgetpu-profile", + param: content, + }); +} diff --git a/media/EdgeTPUCfgEditor/updateUI.js b/media/EdgeTPUCfgEditor/updateUI.js new file mode 100644 index 00000000..2f3f7e0a --- /dev/null +++ b/media/EdgeTPUCfgEditor/updateUI.js @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function updateStepUI(step) { + const allOptionPanels = document.querySelectorAll(".optionPanel .options"); + allOptionPanels.forEach(function (panel) { + panel.style.display = "none"; + }); + + const optionPanel = document.getElementById("option" + step); + optionPanel.style.display = "block"; + + const edgeTPUSearchDelegate = document.getElementById( + "EdgeTPUSearchDelegate" + ); + const edgeTPUDelegateSearchStepDiv = document.getElementById( + "EdgeTPUDelegateSearchStepDiv" + ); + const edgeTPUIntermediateTensors = document.getElementById( + "EdgeTPUIntermediateTensors" + ); + + if (edgeTPUSearchDelegate.checked) { + edgeTPUIntermediateTensors.value = ""; + edgeTPUDelegateSearchStepDiv.style.display = "block"; + } else { + edgeTPUDelegateSearchStepDiv.style.display = "none"; + } + + const allSteps = document.querySelectorAll(".statusbar .steps .step"); + allSteps.forEach(function (step) { + step.classList.remove("current"); + }); + + const stepbar = document.getElementById("stepbar" + step); + stepbar.classList.add("current"); +} + +export function updateEdgeTPUCompileUI() { + const allOptionPanels = document.querySelectorAll(".optionPanel .options"); + allOptionPanels.forEach(function (panel) { + panel.style.display = "none"; + }); + + const edgeTPUBasicOptions = document.getElementById( + "optionImportEdgeTPUBasic" + ); + const edgeTPUAdvancedOptions = document.getElementById( + "optionImportEdgeTPUAdvanced" + ); + const edgeTPUSearchDelegate = document.getElementById( + "EdgeTPUSearchDelegate" + ); + const edgeTPUDelegateSearchStepDiv = document.getElementById( + "EdgeTPUDelegateSearchStepDiv" + ); + + edgeTPUBasicOptions.style.display = "none"; + edgeTPUAdvancedOptions.style.display = "none"; + + edgeTPUDelegateSearchStepDiv.style.display = edgeTPUSearchDelegate.checked + ? "block" + : "none"; + edgeTPUBasicOptions.style.display = "block"; + edgeTPUAdvancedOptions.style.display = "block"; +} diff --git a/media/EdgeTPUCfgEditor/vscodeapi.js b/media/EdgeTPUCfgEditor/vscodeapi.js new file mode 100644 index 00000000..6cdfaf35 --- /dev/null +++ b/media/EdgeTPUCfgEditor/vscodeapi.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const vscode = acquireVsCodeApi(); + +export function postMessageToVsCode(msg) { + vscode.postMessage(msg); +}