├── .eslintrc.js ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SECURITY.md ├── attributes ├── kernel.xml ├── loop.xml └── memory.xml ├── media ├── Analysis │ ├── 5.gif │ ├── 6.gif │ └── 8.gif ├── BuildSingleFile.gif ├── Intelisense.gif ├── PrepareTask │ ├── 4.gif │ ├── 5.gif │ └── 7.gif └── oneapi-logo.png ├── package-lock.json ├── package.json ├── package.nls.json ├── snippets.json ├── src ├── AdvisorLaunchScriptWriter.ts ├── LaunchConfigurator.ts ├── LaunchScriptWriter.ts ├── ProjectSettings.ts ├── VtuneLaunchScriptWriter.ts ├── extension.ts ├── hoverProvider.ts ├── messages.ts ├── test │ ├── runTest.ts │ ├── suite │ │ ├── extension.test.ts │ │ ├── index.ts │ │ └── tool.test.ts │ └── ui │ │ ├── assets │ │ ├── Makefile │ │ ├── hello-world.c │ │ ├── hello-world.cpp │ │ └── matrix_mul_dpcpp.cpp │ │ ├── configs │ │ ├── .mocharc-debug.js │ │ └── settings.json │ │ └── launcherTest.ts └── utils │ ├── CPUAttributes.ts │ ├── snippets.ts │ └── utils.ts ├── third-party-programs.txt └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | es2021: true 5 | }, 6 | extends: [ 7 | 'standard' 8 | ], 9 | parser: '@typescript-eslint/parser', 10 | parserOptions: { 11 | ecmaVersion: 12, 12 | sourceType: 'module' 13 | }, 14 | plugins: [ 15 | '@typescript-eslint' 16 | ], 17 | rules: { 18 | 'no-template-curly-in-string': 'off', 19 | 'no-tabs': 'off', 20 | 'no-mixed-spaces-and-tabs': 'off', 21 | semi: ['error', 'always'], 22 | 'space-before-function-paren': ['error', 'never'], 23 | 'no-redeclare': 'warn', 24 | 'no-throw-literal': 'warn', 25 | 'no-unused-expressions': 'warn', 26 | indent: ['error', 2], 27 | 'linebreak-style': ['error', 'unix'], 28 | quotes: ['error', 'single'], 29 | 'no-empty': 'warn', 30 | 'no-cond-assign': ['error', 'always'], 31 | 'for-direction': 'off', 32 | 'newline-after-var': ['error', 'always'], 33 | 'object-curly-spacing': ['error', 'always'] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | branch_protection_rule: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | permissions: read-all 13 | 14 | jobs: 15 | build-extensions: 16 | name: Build Extension 17 | runs-on: ubuntu-latest 18 | env: 19 | NODE_OPTIONS: "--max-old-space-size=4096" 20 | steps: 21 | - name: Check out repository code 22 | uses: actions/checkout@1e31de5234b9f8995739874a8ce0492dc87873e2 #v4 23 | - name: Build the package 24 | run: npm install && npm run package 25 | - name: Upload artifact 26 | uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 #v4 27 | with: 28 | name: launcher-extension 29 | path: ./*.vsix 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | .DS_Store 4 | test-resources/ 5 | *.vsix 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "dbaeumer.vscode-eslint" 6 | ] 7 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | { 6 | "version": "0.2.0", 7 | "configurations": [ 8 | { 9 | "name": "Run Extension", 10 | "type": "extensionHost", 11 | "request": "launch", 12 | "runtimeExecutable": "${execPath}", 13 | "args": [ 14 | "--extensionDevelopmentPath=${workspaceFolder}" 15 | ], 16 | "outFiles": [ 17 | "${workspaceFolder}/out/**/*.js" 18 | ], 19 | "preLaunchTask": "npm: watch" 20 | }, 21 | { 22 | "name": "Extension Tests", 23 | "type": "extensionHost", 24 | "request": "launch", 25 | "runtimeExecutable": "${execPath}", 26 | "args": [ 27 | "--extensionDevelopmentPath=${workspaceFolder}", 28 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 29 | ], 30 | "outFiles": [ 31 | "${workspaceFolder}/out/test/**/*.js" 32 | ], 33 | "preLaunchTask": "npm: watch" 34 | }, 35 | { 36 | "name": "Debug UI Tests", 37 | "type": "node", 38 | "request": "launch", 39 | "program": "${workspaceFolder}/node_modules/.bin/extest", 40 | "args": [ 41 | "setup-and-run", 42 | "${workspaceFolder}/out/test/ui/*.js", 43 | "--mocha_config", 44 | "${workspaceFolder}/src/test/ui/configs/.mocharc-debug.js" 45 | ], 46 | "console": "integratedTerminal", 47 | "internalConsoleOptions": "neverOpen" 48 | } 49 | ] 50 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "out": false 4 | }, 5 | "search.exclude": { 6 | "out": true 7 | }, 8 | "typescript.tsc.autoDetect": "off" 9 | } 10 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // See https://go.microsoft.com/fwlink/?LinkId=733558 2 | // for the documentation about the tasks.json format 3 | { 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "npm", 8 | "script": "watch", 9 | "problemMatcher": "$tsc-watch", 10 | "isBackground": true, 11 | "presentation": { 12 | "reveal": "never" 13 | }, 14 | "group": "build" 15 | }, 16 | { 17 | "type": "npm", 18 | "script": "compile", 19 | "group": { 20 | "kind": "build", 21 | "isDefault": true 22 | } 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | test-data/** 11 | test-resources/** 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | ## 0.1.28 3 | 4 | - CVE Vulnerability Fixes 5 | 6 | ## 0.1.27 7 | 8 | - 3rd Party component dependency version update - Bumps micromatch 9 | 10 | ## 0.1.26 11 | 12 | - 3rd Party component dependency version update 13 | 14 | ## 0.1.25 15 | 16 | - Updated extension name 17 | - Minor bugfixes 18 | 19 | ## 0.1.24 20 | 21 | - Refactoring errors 22 | - Added sycl snippets and tooltips 23 | 24 | ## 0.1.23 25 | 26 | - Updated versions of 3rd party dependencies 27 | 28 | ## 0.1.22 29 | 30 | - Updated version of 'word-wrap' dependency 31 | 32 | ## 0.1.21 33 | 34 | - Updated versions of 3rd party dependencies 35 | - Fixed bug for powershell command 36 | 37 | ## 0.1.20 38 | 39 | - Updated versions of 3rd party dependencies 40 | 41 | ## 0.1.19 42 | 43 | - Updated version of 'xml2js' dependency 44 | 45 | ## 0.1.18 46 | 47 | - Automatically add path to compiler and include paths into .vscode/settings.json file 48 | - Suggests to install C++ extension pack if there's no one 49 | 50 | ## 0.1.17 51 | 52 | - Updated version of 'http-cache-semantics' dependency 53 | 54 | ## 0.1.16 55 | 56 | - Updated version of 'json5' dependency 57 | 58 | ## 0.1.15 59 | 60 | - Updated log messages and extension name 61 | 62 | ## 0.1.14 63 | 64 | - Analyzers running script is moved into working directory 65 | - Improved settings usage 66 | - Added check for executable files to analyze 67 | 68 | ## 0.1.3 69 | 70 | - Added check for avoiding conflicts with deprecated versions of extensions. 71 | - Code completion snippets & tooltips for FPGA attributes. 72 | - Fixed bugs. 73 | 74 | ## 0.0.15 75 | 76 | - Function for generating launch configuration moved to GDB with GPU Debug Support for Intel® oneAPI Toolkits; 77 | - Fixed several minor bugs. 78 | 79 | ## 0.0.14 80 | 81 | - Updated launch configuration for GPU debugging compatibility. 82 | 83 | ## 0.0.13 84 | 85 | - Added functions for generating tasks and launch configuration; 86 | - Added a functions for quick build the currently open cpp file; 87 | - Added tip on installing Environment Configurator for Intel® oneAPI Toolkits; 88 | - Added instructions for configuring IntelliSense. 89 | 90 | ## 0.0.12 91 | 92 | - Update Readme with extra doc link. 93 | 94 | ## 0.0.11 95 | 96 | - Update Logo. 97 | 98 | ## 0.0.10 99 | 100 | - Change default location of VTune Profiler on macOS; 101 | - Change Advisor GUI executable. 102 | 103 | ## 0.0.9 104 | 105 | - First non-preview release; 106 | - Added tags to manifest for discoverability in marketplace. 107 | 108 | ## 0.0.8 109 | 110 | - Change default install location for the tools; 111 | - Fix typos in README.md. 112 | 113 | ## 0.0.7 114 | 115 | - Update logo and README.md. 116 | 117 | ## 0.0.6 118 | 119 | - Initial release 120 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | SPDX-License-Identifier: MIT 3 | 4 | Copyright (c) Intel Corporation 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Analysis Configurator for Intel Software Developer Tools 2 | 3 | #### [Repository](https://github.com/intel/vscode-oneapi-analysis-configurator)  |  [Issues](https://github.com/intel/vscode-oneapi-analysis-configurator/issues)  |  [Documentation](https://www.intel.com/content/www/us/en/developer/tools/oneapi/documentation.html)  |  [Samples](https://github.com/oneapi-src/oneAPI-samples)  |  [Forums](https://community.intel.com/t5/Intel-oneAPI-Toolkits/ct-p/oneapi) 4 | 5 | This extension provides integration of your project with the Intel® VTune™ 6 | Profiler and Intel® Advisor analysis tools. It also makes it easier to 7 | configure your oneAPI C/++ projects for building, running and debugging your 8 | application with Visual Studio Code* (VS Code). 9 | 10 | 11 | - [Intel® VTune™ Profiler](https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html) 12 | is a performance profiling tool that provides advanced sampling and profiling 13 | techniques to quickly analyze code, isolate issues and deliver insights for 14 | optimizing performance on modern processors. 15 | 16 | 17 | - [Intel® Advisor](https://www.intel.com/content/www/us/en/develop/documentation/get-started-with-advisor/top.html) 18 | is for software architects and developers who need the right information and 19 | recommendations to make the best design and optimization decisions for 20 | efficient vectorization, threading, and offloading to accelerators. 21 | 22 | For details on which compiler options to use with the Intel® VTune™ Profiler, 23 | see the [Setup Analysis Target](https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top/set-up-analysis-target.html) 24 | section of the [Intel® VTune™ Profiler User Guide](https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top.html). 25 | 26 | For details on which compiler options to use with the Intel® Advisor, see the 27 | [Build Target Application](https://www.intel.com/content/www/us/en/develop/documentation/advisor-user-guide/top/set-up-project/build-target.html) 28 | section of the [Intel® Advisor User Guide](https://www.intel.com/content/www/us/en/develop/documentation/advisor-user-guide/top.html). 29 | 30 | ## Where to find Intel oneAPI toolkits 31 | 32 | This extension does not provide any of the tools that are required to perform 33 | profiling or analysis. 34 | 35 | Please visit https://www.intel.com/oneapi for details. For more 36 | information on how to use Visual Studio Code with Intel oneAPI toolkits, 37 | please visit [Using VS Code with Intel oneAPI toolkits](https://www.intel.com/content/www/us/en/develop/documentation/using-vs-code-with-intel-oneapi/top.html). 38 | 39 | 40 | 41 | ## Preparing Tasks from Make / CMake Files 42 | 1. Using the VS Code explorer, click `File -> Open Folder`. 43 | 2. Navigate to the folder where your project is located and click `OK`. 44 | (In our case it is oneAPI sample "Simple Add") 45 | 3. Press `Ctrl+Shift+P ( or View -> Command Palette... )` to open the 46 | Command Palette. 47 | 4. Type **Intel oneAPI** and select `Intel oneAPI: Generate tasks`. 48 | 49 | ![image](media/PrepareTask/4.gif) 50 | 51 | 5. Follow the prompts to add targets from your make/cmake oneAPI project. 52 | 53 | ![image](media/PrepareTask/5.gif) 54 | 55 | 6. Run the target by selecting `Terminal > Run task...` or by 56 | `Tasks: Run Task` from Command Palette. 57 | 7. Select the task to run. 58 | 59 | ![image](media/PrepareTask/7.gif) 60 | 61 | ## Building a single cpp file: 62 | 1. Open the cpp file you want to build. 63 | 2. Press `Ctrl+Shift+P` ( or `View -> Command Palette...` ) to open the 64 | Command Palette. 65 | 3. Type **Intel oneAPI** and select 66 | `Intel oneAPI: Quick build current file with ICPX`. 67 | 4. If you want to build a file with SYCL enabled, choose the option 68 | `Intel oneAPI: Quick build current file with ICPX and SYCL enabled`. 69 | 70 | ![image](media/BuildSingleFile.gif) 71 | 72 | ## Using Intel analysis tools 73 | You need to have at least one of the above Intel analysis tools installed for 74 | this extension to work and be useful. 75 | 1. Open a Visual Studio Code project. 76 | 2. Build your project to create the executable you plan to analyze (run proper 77 | task from previous steps). 78 | 3. Press `Ctrl+Shift+P` ( or `View -> Command Palette...` ) to open the 79 | Command Palette in VS Code. 80 | 4. Type **Intel oneAPI** and select `Intel oneAPI:Launch Advisor` or 81 | `Intel oneAPI: Launch VTune Profiler`. 82 | 5. Select the executable you want to analyze. This needs to be done once for a 83 | workspace unless you want to analyze a different executable. 84 | 85 | ![image](media/Analysis/5.gif) 86 | 87 | 6. Select the installation path of the tool * Intel Advisor or Intel VTune 88 | Profiler. This needs to be done once for a workspace. 89 | 90 | ![image](media/Analysis/6.gif) 91 | 92 | 7. Enter the name of the tool`s project folder, or press enter to accept the 93 | default. This needs to be done once for a workspace. 94 | 8. The extension will open the Intel VTune Profiler and pass the appropriate project 95 | parameters to the tool. 96 | 97 | ![image](media/Analysis/8.gif) 98 | 99 | ## How to Use IntelliSense for Code Developed with Intel oneAPI Toolkits 100 | 101 | ### Configure C++ Properties 102 | 103 | This extension provides the ability to configure the cpp properties 104 | includePath, defines, and compilerPath. 105 | 1. Press `Ctrl+Shift+P` ( or `View -> Command Palette...` ) to open the 106 | Command Palette in VS Code. 107 | 2. Type `Intel oneAPI: configure cpp properties configuration` and select it 108 | from the palette. 109 | 3. Select cpp standard. 110 | 4. Select c standard. 111 | 5. A message will appear in the lower right corner to confirm the properties 112 | have been configured. 113 | 114 | ![image](media/Intelisense.gif) 115 | 116 | To view or change the properties, open settings.json from the VS Code Explorer. 117 | 118 | To make changes to the configuration, edit the default path in settings.json. 119 | 120 | ## IntelliSense for basic code hints for FPGA Memory Attributes and CPU pragmas 121 | - While typing some of the Attributes/Pragmas, there will be suggestions with 122 | a description of what function should you use. 123 | - The description with the common usage will be visible when hovering a cursor 124 | over a Attribute or Pragma in your code. 125 | 126 | FPGA Loop Directives, FPGA Memory Attributes, FPGA Kernel Attributes and CPU 127 | pragmas are supported. 128 | [Learn more about FPGA Attributes](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-fpga-optimization-guide/top/quick-reference.html) 129 | [Learn more about CPU pragmas](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference.html) 130 | 131 | ## Contributing 132 | Install Visual Studio Code (at least version 1.42) and open this project within 133 | it. You also need `node + npm`. 134 | - Switch to project root folder 135 | - `npm install` 136 | - `code .` 137 | 138 | At this point you should be able to run the extension in the 139 | "Extension Development Host". 140 | 141 | ## License 142 | This extension is released under the MIT License. 143 | 144 | *Other names and brands may be claimed as the property of others. 145 | 146 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. 3 | 4 | ## Reporting a Vulnerability 5 | Please report any security vulnerabilities in this project [utilizing the guidelines here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). -------------------------------------------------------------------------------- /attributes/kernel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FPGA Kernel Attributes 5 | 6 |
7 |

The following table summarizes kernel attributes: 8 |

9 |
10 | 11 | FPGA Kernel Attributes 12 | 13 | 14 | 15 | 16 | 17 | Attribute 18 | 19 | Description 20 | 21 | Example 22 | 23 | 24 | 25 | 26 | 27 | [[intel::scheduler_target_fmax_mhz(N)]] 28 | 29 | Determines the pipelining effort the scheduler attempts during the scheduling process. 30 | 31 | 32 | [[intel::scheduler_target_fmax_mhz(SCHEDULER_TARGET_FMAX)]] { 33 | for (unsigned i = 0; i < SIZE; i++) { 34 | accessorRes[0] += accessorIdx[i] * 2; 35 | } 36 | }); 37 | 38 | 39 | 40 | [[intel::max_work_group_size(Z, Y, X)]] 41 | 42 | 43 |

Specifies a maximum or the required work-group size for optimizing hardware use of the DPC++ kernel without involving excess logic. 44 |

45 |
46 | 47 | [[intel::max_work_group_size(1,1,MAX_WG_SIZE)]] { 48 | accessorRes[wiID] = accessorIdx[wiID] * 2; 49 | }); 50 | 51 |
52 | 53 | [[intel::max_global_work_dim(0)]] 54 | 55 | 56 |

Omits logic that generates and dispatches global, local, and group IDs into the compiled kernel. 57 |

58 |
59 | 60 | [[intel::max_global_work_dim(0)]] { 61 | for (unsigned i = 0; i < SIZE; i++) { 62 | accessorRes[i] = accessorIdx[i] * 2; 63 | } 64 | } 65 | 66 |
67 | 68 | [[intel::num_simd_work_items(N)] 69 | 70 | 71 |

Specifies the number of work items within a work group that the compiler executes in a SIMD or vectorized manner. 72 |

73 |
74 | 75 | [[intel::num_simd_work_items(NUM_SIMD_WORK_ITEMS), 76 | cl::reqd_work_group_size(1,1,REQD_WORK_GROUP_SIZE)]] { 77 | accessorRes[wiID] = sqrt(accessorIdx[wiID]); 78 | }); 79 | 80 |
81 | 82 | [[intel::no_global_work_offset(1)]] 83 | 84 | 85 |

Omits generating hardware required to support global work offsets. 86 |

87 |
88 | 89 | [[intel::no_global_work_offset(1))]] { 90 | accessorRes[wiID] = accessorIdx[wiID] * 2; 91 | } 92 | 93 |
94 | 95 | [[intel::kernel_args_restrict]] 96 | 97 | 98 |

Ignores the dependencies between accessor arguments in a DPC++ kernel. 99 |

100 |
101 | 102 | [[intel::kernel_args_restrict]] { 103 | for (unsigned i = 0; i < size; i++) { 104 | out_accessor[i] = in_accessor[i]; 105 | } 106 | }); 107 | 108 |
109 | 110 | [[intel::use_stall_enable_clusters]] 111 | 112 | 113 |

Reduces the area and latency of your kernel. 114 |

115 |
116 | 117 | h.single_task<class KernelComputeStallFree>( [=]() [[intel::use_stall_enable_clusters]] { 118 | // The computations in this device kernel uses Stall Enable Clusters 119 | Work(accessor_vec_a, accessor_vec_b, accessor_res); 120 | }); 121 | }); 122 | 123 |
124 | 125 | 126 |
127 |
128 |
-------------------------------------------------------------------------------- /attributes/loop.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FPGA Loop Directives 5 | 6 |

The following table summarizes loop directives: 7 |

8 | 9 | FPGA Loop Directives 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

Pragma or Attribute 18 |

19 |
20 | 21 |

Description 22 |

23 |
24 | 25 |

Example 26 |

27 |
28 |
29 | 30 | 31 | 32 | disable_loop_pipelining 33 | 34 | 35 |

Directs the 36 | to disable pipelining of a loop. 37 |

38 |
39 | 40 | [[intel::disable_loop_pipelining]] 41 | for (int i = 1; i < N; i++) { 42 | int j = a[i-1]; 43 | // Memory dependency induces a high-latency loop feedback path 44 | a[i] = foo(j) 45 | } 46 | 47 |
48 | 49 | 50 | initiation_interval 51 | 52 | 53 |

Forces a loop to have a loop initialization interval (II) of a specified value. 54 |

55 |
56 | 57 | // ii set to 5 58 | [[intel::initiation_interval(5)]] 59 | for (int i = 0; i < N; ++i){ 60 | } 61 | 62 |
63 | 64 | 65 | ivdep 66 | 67 | 68 |

Ignores memory dependencies between iterations of this loop 69 |

70 |
71 | 72 | // ivdep loop 73 | [[intel::ivdep]] for (…) {} 74 | //ivdep safelen 75 | [[intel::ivdep(safelen)]] for (;;) {} 76 | // ivdep accessor 77 | [[intel::ivdep(accessorA)]] for (;;) {} 78 | //ivdep array safelen 79 | [[intel::ivdep(accessorA, safelen)]] 80 | for (;;){} 81 | 82 |
83 | 84 | loop_coalesce 85 | 86 | 87 |

Coalesces nested loops into a single loop without affecting the loop functionality. 88 |

89 |
90 | 91 | [[intel::loop_coalesce(2)]] 92 | for (int i = 0; i < N; i++) 93 | for (int j = 0; j < M; j++) 94 | sum[i][j] += i+j; 95 | 96 |
97 | 98 | 99 | max_concurrency 100 | 101 | 102 |

Limits the number of iterations of a loop that can simultaneously execute at any time. 103 |

104 |
105 | 106 | //max concurrency set to 1 107 | [[intel::max_concurrency(1)]] 108 | for (int i = 0; i < c; ++i){ 109 | } 110 | 111 |
112 | 113 | max_interleaving 114 | 115 | 116 |

Maximizes the throughput and hardware resource occupancy of pipelined inner loops in a loop nest. 117 |

118 |
119 | 120 | // Loop j is pipelined with ii=1 121 | for (int j = 0; j < M; j++) { 122 | int a[N]; 123 | // Loop i is pipelined with ii=2 124 | [[intel::max_interleaving(1)]] 125 | for (int i = 1; i < N; i++) { 126 | a[i] = foo(i) 127 | } 128 | … 129 | } 130 | 131 |
132 | 133 | speculated_iterations 134 | 135 | 136 |

Improves the performance of pipelined loops. 137 |

138 |
139 | 140 | [[intel::speculated_iterations(1)]] 141 | while (m*m*m < N) { 142 | m += 1; 143 | } 144 | dst[0] = m; 145 | 146 |
147 | 148 | unroll 149 | 150 | 151 |

Unrolls a loop in the kernel code. 152 |

153 |
154 | 155 | // unroll factor N set to 2 156 | #pragma unroll 2 157 | for(size_t k = 0; k < 4; k++){ 158 | mac += data_in[(gid * 4) + k] * coeff[k]; 159 | } 160 | 161 |
162 | 163 | 164 |
165 |
166 |
167 | -------------------------------------------------------------------------------- /attributes/memory.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FPGA Memory Attributes 5 | 6 |

The following table summarizes memory attributes: 7 |

8 | 9 | FPGA Memory Attributes 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |

Attribute 18 |

19 |
20 | 21 |

Description 22 |

23 |
24 | 25 |

Example 26 |

27 |
28 |
29 | 30 | 31 | 32 | bank_bits 33 | 34 | 35 |

Specifies that the local memory addresses should use bits for bank selection. 36 |

37 |
38 | 39 | // Array is implemented with 4 banks where 40 | // bits 6 and 5 of the memory word address 41 | // are used to select between the banks 42 | [[intel::bank_bits(6,5)]] int array[128]; 43 | 44 | 45 |
46 | 47 | 48 | bankwidth 49 | 50 | 51 |

Specifies that the memory implementing the variable or array must have memory banks of a defined width. 52 |

53 |
54 | 55 | // Each memory bank is 8 bytes (64-bits) wide 56 | [[intel::bankwidth(8)]] int array[128]; 57 | 58 |
59 | 60 | 61 | doublepump 62 | 63 | 64 |

Specifies that the memory implementing the variable, or an array must be clocked at twice the rate as the kernel accessing it. 65 |

66 |
67 | 68 | // Array is implemented in a memory that operates at 69 | // twice the clock frequency of the kernel 70 | [[intel::doublepump, bankwidth(128)]] int array[128]; 71 | 72 |
73 | 74 | force_pow2_depth 75 | 76 | 77 |

Specifies that the memory implementing the variable or array has a power-of-2 depth. 78 |

79 |
80 | 81 | // array1 is implemented in a memory with depth 1536 82 | [[intel::force_pow2_depth(0)]] int array1[1536]; 83 | 84 |
85 | 86 | 87 | max_replicates 88 | 89 | 90 | 91 |

Specifies that the memory implementing the variable, or an array has no more than the specified number of replicates to enable simultaneous accesses from the datapath. 92 |

93 |
94 | 95 | // Array is implemented in a memory with maximum four 96 | // replicates 97 | [[intel::max_replicates(4)]] int array[128]; 98 | 99 |
100 | 101 | 102 | fpga_memory 103 | 104 | 105 |

Forces a variable or an array to be implemented as an embedded memory. 106 |

107 |
108 | 109 | // Array is implemented in memory (MLAB/M20K), 110 | // the actual implementation is automatically decided 111 | // by the compiler 112 | [[intel::fpga_memory]] int array1[128]; 113 | 114 | // Array is implemented in M20K 115 | [[intel::fpga_memory("BLOCK_RAM")]] int array2[64]; 116 | 117 | // Array is implemented in MLAB 118 | [[intel::fpga_memory("MLAB")]] int array3[64]; 119 | 120 |
121 | 122 | 123 | merge 124 | 125 | 126 |

Allows merging of two or more variables or arrays defined in the same scope with respect to width or depth. 127 |

128 |
129 | 130 | // Both arrays are merged width-wise and implemented 131 | // in the same memory system 132 | [[intel::merge("mem", "width")]] short arrayA[128]; 133 | [[intel::merge("mem", "width")]] short arrayB[128]; 134 | 135 |
136 | 137 | 138 | numbanks 139 | 140 | 141 |

Specifies that the memory implementing the variable or array must have a defined number of memory banks. 142 |

143 |
144 | 145 | // Array is implemented with 2 banks 146 | [[intel::numbanks(2)]] int array[128]; 147 | 148 |
149 | 150 | 151 | private_copies 152 | 153 | 154 |

Specifies that the memory implementing the variable, or an array has no more than the specified number of independent copies to enable concurrent thread or loop iteration accesses. 155 |

156 |
157 | 158 | // Array is implemented in a memory with two 159 | // private copies 160 | [[intel::private_copies(2)]] int array[128]; 161 | 162 |
163 | 164 | 165 | fpga_register 166 | 167 | 168 |

Forces a variable or an array to be carried through the pipeline in registers. 169 |

170 |
171 | 172 | // Array is implemented in register 173 | [[intel::fpga_register]] int array[128]; 174 | 175 |
176 | 177 | 178 | simple_dual_port 179 | 180 | 181 |

Specifies that the memory implementing the variable or array should have no port that serves both reads and writes. 182 |

183 |
184 | 185 | // Array is implemented in a memory such that no 186 | // single port serves both a read and a write 187 | [[intel::simple_dual_port]] int array[128]; 188 | 189 |
190 | 191 | 192 | singlepump 193 | 194 | 195 |

Specifies that the memory implementing the variable or array must be clocked at the same rate as the kernel accessing it. 196 |

197 |
198 | 199 | // Array is implemented in a memory that operates 200 | // at the same clock frequency as the kernel 201 | [[intel::singlepump]] int array[128]; 202 | 203 |
204 | 205 | 206 |
207 |
208 |
209 | -------------------------------------------------------------------------------- /media/Analysis/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/Analysis/5.gif -------------------------------------------------------------------------------- /media/Analysis/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/Analysis/6.gif -------------------------------------------------------------------------------- /media/Analysis/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/Analysis/8.gif -------------------------------------------------------------------------------- /media/BuildSingleFile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/BuildSingleFile.gif -------------------------------------------------------------------------------- /media/Intelisense.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/Intelisense.gif -------------------------------------------------------------------------------- /media/PrepareTask/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/PrepareTask/4.gif -------------------------------------------------------------------------------- /media/PrepareTask/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/PrepareTask/5.gif -------------------------------------------------------------------------------- /media/PrepareTask/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/PrepareTask/7.gif -------------------------------------------------------------------------------- /media/oneapi-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-oneapi-analysis-configurator/4fa62f9534221ae52d883194419c4774fdac48b9/media/oneapi-logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oneapi-analysis-configurator", 3 | "displayName": "Analysis Configurator for Intel Software Developer Tools", 4 | "description": "Build and performance analysis of your Intel® oneAPI applications.", 5 | "publisher": "intel-corporation", 6 | "version": "0.1.28", 7 | "license": "MIT", 8 | "icon": "media/oneapi-logo.png", 9 | "keywords": [ 10 | "intel", 11 | "oneapi", 12 | "Advisor", 13 | "vtune", 14 | "iot" 15 | ], 16 | "engines": { 17 | "vscode": "^1.81.0" 18 | }, 19 | "categories": [ 20 | "Snippets", 21 | "Other" 22 | ], 23 | "activationEvents": [ 24 | "onStartupFinished" 25 | ], 26 | "main": "./out/extension.js", 27 | "contributes": { 28 | "snippets": [ 29 | { 30 | "language": "cpp", 31 | "path": "./snippets.json" 32 | } 33 | ], 34 | "commands": [ 35 | { 36 | "command": "intel-corporation.oneapi-analysis-configurator.generateTaskJson", 37 | "title": "Intel oneAPI: Generate tasks" 38 | }, 39 | { 40 | "command": "intel-corporation.oneapi-analysis-configurator.quickBuild", 41 | "title": "Intel oneAPI: Quick build current file with ICPX" 42 | }, 43 | { 44 | "command": "intel-corporation.oneapi-analysis-configurator.quickBuildSycl", 45 | "title": "Intel oneAPI: Quick build current file with ICPX and SYCL enabled" 46 | }, 47 | { 48 | "command": "intel-corporation.oneapi-analysis-configurator.launchAdvisor", 49 | "title": "Intel oneAPI: Launch Advisor" 50 | }, 51 | { 52 | "command": "intel-corporation.oneapi-analysis-configurator.launchVTune", 53 | "title": "Intel oneAPI: Launch VTune Profiler" 54 | }, 55 | { 56 | "command": "intel-corporation.oneapi-analysis-configurator.configureCppProperties", 57 | "title": "Intel oneAPI: Configure cpp properties configuration" 58 | } 59 | ], 60 | "configuration": [ 61 | { 62 | "title": "Analysis Configurator for Intel Software Developer Tools", 63 | "properties": { 64 | "intel-corporation.oneapi-analysis-configurator.ONEAPI_ROOT": { 65 | "type": "string", 66 | "description": "%capabilities.ONEAPI_ROOT.description%" 67 | }, 68 | "intel-corporation.oneapi-analysis-configurator.binary-path": { 69 | "type": "string", 70 | "description": "Path of the executable to analyze", 71 | "scope": "resource" 72 | }, 73 | "intel-corporation.oneapi-analysis-configurator.advisor.install-root": { 74 | "type": "string", 75 | "description": "Root install location for Intel® Advisor", 76 | "scope": "window" 77 | }, 78 | "intel-corporation.oneapi-analysis-configurator.vtune.install-root": { 79 | "type": "string", 80 | "description": "Root install location for Intel® VTune™ Profiler", 81 | "scope": "window" 82 | }, 83 | "intel-corporation.oneapi-analysis-configurator.advisor.project-folder": { 84 | "type": "string", 85 | "description": "Path of the Intel® Advisor project folder", 86 | "scope": "resource" 87 | }, 88 | "intel-corporation.oneapi-analysis-configurator.vtune.project-folder": { 89 | "type": "string", 90 | "description": "Path of the Intel® VTune™ Profiler project folder", 91 | "scope": "resource" 92 | } 93 | } 94 | } 95 | ], 96 | "taskDefinitions": [ 97 | { 98 | "type": "toolProvider", 99 | "properties": { 100 | "test1": { 101 | "type": "string", 102 | "description": "Testing" 103 | } 104 | } 105 | } 106 | ] 107 | }, 108 | "scripts": { 109 | "vscode:prepublish": "npm run compile", 110 | "compile": "tsc -p ./", 111 | "watch": "tsc -watch -p ./", 112 | "pretest": "npm run compile", 113 | "test": "node ./out/test/runTest.js", 114 | "lint": "eslint --ext .ts --fix ./src/*", 115 | "package": "vsce package", 116 | "snippets": "npm run compile | node ./out/utils/snippets.js", 117 | "ui-test": "extest setup-and-run -o ./src/test/ui/configs/settings.json --yarn out/test/ui/*.js" 118 | }, 119 | "devDependencies": { 120 | "@types/chai": "^4.3.5", 121 | "@types/mkdirp": "^1.0.2", 122 | "@types/mocha": "^10.0.1", 123 | "@types/node": "^20.5.0", 124 | "@types/rimraf": "^3.0.2", 125 | "@types/vscode": "^1.81.0", 126 | "@typescript-eslint/eslint-plugin": "^6.4.0", 127 | "@typescript-eslint/parser": "^6.4.0", 128 | "@vscode/vsce": "^2.20.1", 129 | "chai": "^4.3.7", 130 | "eslint": "^8.47.0", 131 | "eslint-config-standard": "^17.1.0", 132 | "eslint-plugin-import": "^2.28.0", 133 | "eslint-plugin-n": "^16.0.1", 134 | "eslint-plugin-node": "^11.1.0", 135 | "eslint-plugin-promise": "^6.1.1", 136 | "mocha": "^10.8.2", 137 | "typescript": "^5.1.6", 138 | "vscode-extension-tester": "^5.9.0", 139 | "vscode-test": "^1.5.2" 140 | }, 141 | "repository": { 142 | "type": "git", 143 | "url": "https://github.com/intel/vscode-oneapi-analysis-configurator.git" 144 | }, 145 | "dependencies": { 146 | "xml2js": "^0.6.2" 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /package.nls.json: -------------------------------------------------------------------------------- 1 | { 2 | "capabilities.ONEAPI_ROOT.description" : "Absolute path to oneAPI installation folder.\n\nSpecifies the absolute pathname to your oneAPI installation. This path is useful for automatically configure your cpp properties . If ONEAPI_ROOT variable is not set, it takes existing ONEAPI_ROOT variable from oneapi-environment-configurator extention.\n\n" 3 | } 4 | -------------------------------------------------------------------------------- /snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | " ": { 3 | "prefix": "intel", 4 | "body": [ 5 | "intel::" 6 | ], 7 | "description": " " 8 | }, 9 | "scheduler_target_fmax_mhz(N)": { 10 | "description": "The schedule fmax target determines the pipelining effort the scheduler attempts during the scheduling process.", 11 | "prefix": "intel::scheduler_target_fmax_mhz", 12 | "body": [ 13 | "intel::scheduler_target_fmax_mhz" 14 | ] 15 | }, 16 | "max_work_group_size(Z, Y, X)": { 17 | "description": "Specifies a maximum or the required work-group size for optimizing hardware use of the DPC++ kernel without involving excess logic.", 18 | "prefix": "intel::max_work_group_size", 19 | "body": [ 20 | "intel::max_work_group_size" 21 | ] 22 | }, 23 | "max_global_work_dim(0)": { 24 | "description": "Omits logic that generates and dispatches global, local, and group IDs into the compiled kernel.", 25 | "prefix": "intel::max_global_work_dim", 26 | "body": [ 27 | "intel::max_global_work_dim" 28 | ] 29 | }, 30 | "num_simd_work_items(N)": { 31 | "description": "Specifies the number of work items within a work group that the compiler executes in a SIMD or vectorized manner.", 32 | "prefix": "intel::num_simd_work_items", 33 | "body": [ 34 | "intel::num_simd_work_items" 35 | ] 36 | }, 37 | "no_global_work_offset(1)": { 38 | "description": "Omits generating hardware required to support global work offsets.", 39 | "prefix": "intel::no_global_work_offset", 40 | "body": [ 41 | "intel::no_global_work_offset" 42 | ] 43 | }, 44 | "kernel_args_restrict": { 45 | "description": "Ignores the dependencies between accessor arguments in a DPC++ kernel.", 46 | "prefix": "intel::kernel_args_restrict", 47 | "body": [ 48 | "intel::kernel_args_restrict" 49 | ] 50 | }, 51 | "use_stall_enable_clusters": { 52 | "description": "Reduces the area and latency of your kernel.", 53 | "prefix": "intel::use_stall_enable_clusters", 54 | "body": [ 55 | "intel::use_stall_enable_clusters" 56 | ] 57 | }, 58 | "disable_loop_pipelining": { 59 | "description": "Directs the to disable pipelining of a loop.", 60 | "prefix": "disable_loop_pipelining", 61 | "body": [ 62 | "disable_loop_pipelining" 63 | ] 64 | }, 65 | "initiation_interval": { 66 | "description": "Forces a loop to have a loop initialization interval (II) of a specified value.", 67 | "prefix": "initiation_interval", 68 | "body": [ 69 | "initiation_interval" 70 | ] 71 | }, 72 | "ivdep": { 73 | "description": "Ignores memory dependencies between iterations of this loop", 74 | "prefix": "ivdep", 75 | "body": [ 76 | "ivdep" 77 | ] 78 | }, 79 | "loop_coalesce": { 80 | "description": "Coalesces nested loops into a single loop without affecting the loop functionality.", 81 | "prefix": "loop_coalesce", 82 | "body": [ 83 | "loop_coalesce" 84 | ] 85 | }, 86 | "max_concurrency": { 87 | "description": "Limits the number of iterations of a loop that can simultaneously execute at any time.", 88 | "prefix": "max_concurrency", 89 | "body": [ 90 | "max_concurrency" 91 | ] 92 | }, 93 | "max_interleaving": { 94 | "description": "Maximizes the throughput and hardware resource occupancy of pipelined inner loops in a loop nest.", 95 | "prefix": "max_interleaving", 96 | "body": [ 97 | "max_interleaving" 98 | ] 99 | }, 100 | "speculated_iterations": { 101 | "description": "Improves the performance of pipelined loops.", 102 | "prefix": "speculated_iterations", 103 | "body": [ 104 | "speculated_iterations" 105 | ] 106 | }, 107 | "unroll": { 108 | "description": "Unrolls a loop in the kernel code.", 109 | "prefix": "unroll", 110 | "body": [ 111 | "unroll" 112 | ] 113 | }, 114 | "bank_bits": { 115 | "description": "Specifies that the local memory addresses should use bits for bank selection.", 116 | "prefix": "bank_bits", 117 | "body": [ 118 | "bank_bits" 119 | ] 120 | }, 121 | "bankwidth": { 122 | "description": "Specifies that the memory implementing the variable or array must have memory banks of a defined width.", 123 | "prefix": "bankwidth", 124 | "body": [ 125 | "bankwidth" 126 | ] 127 | }, 128 | "doublepump": { 129 | "description": "Specifies that the memory implementing the variable, or an array must be clocked at twice the rate as the kernel accessing it.", 130 | "prefix": "doublepump", 131 | "body": [ 132 | "doublepump" 133 | ] 134 | }, 135 | "force_pow2_depth": { 136 | "description": "Specifies that the memory implementing the variable or array has a power-of-2 depth.", 137 | "prefix": "force_pow2_depth", 138 | "body": [ 139 | "force_pow2_depth" 140 | ] 141 | }, 142 | "max_replicates": { 143 | "description": "Specifies that the memory implementing the variable, or an array has no more than the specified number of replicates to enable simultaneous accesses from the datapath.", 144 | "prefix": "max_replicates", 145 | "body": [ 146 | "max_replicates" 147 | ] 148 | }, 149 | "fpga_memory": { 150 | "description": "Forces a variable or an array to be implemented as an embedded memory.", 151 | "prefix": "fpga_memory", 152 | "body": [ 153 | "fpga_memory" 154 | ] 155 | }, 156 | "merge": { 157 | "description": "Allows merging of two or more variables or arrays defined in the same scope with respect to width or depth.", 158 | "prefix": "merge", 159 | "body": [ 160 | "merge" 161 | ] 162 | }, 163 | "numbanks": { 164 | "description": "Specifies that the memory implementing the variable or array must have a defined number of memory banks.", 165 | "prefix": "numbanks", 166 | "body": [ 167 | "numbanks" 168 | ] 169 | }, 170 | "private_copies": { 171 | "description": "Specifies that the memory implementing the variable, or an array has no more than the specified number of independent copies to enable concurrent thread or loop iteration accesses.", 172 | "prefix": "private_copies", 173 | "body": [ 174 | "private_copies" 175 | ] 176 | }, 177 | "fpga_register": { 178 | "description": "Forces a variable or an array to be carried through the pipeline in registers.", 179 | "prefix": "fpga_register", 180 | "body": [ 181 | "fpga_register" 182 | ] 183 | }, 184 | "simple_dual_port": { 185 | "description": "Specifies that the memory implementing the variable or array should have no port that serves both reads and writes.", 186 | "prefix": "simple_dual_port", 187 | "body": [ 188 | "simple_dual_port" 189 | ] 190 | }, 191 | "singlepump": { 192 | "description": "Specifies that the memory implementing the variable or array must be clocked at the same rate as the kernel accessing it.", 193 | "prefix": "singlepump", 194 | "body": [ 195 | "singlepump" 196 | ] 197 | }, 198 | "alloc_section(var1,var2,..., 'r;attribute-list')": { 199 | "description": "Allocates one or more variables in the specified section. Controls section attribute specification for variables.", 200 | "prefix": "#pragma alloc_section", 201 | "body": [ 202 | "#pragma alloc_section" 203 | ] 204 | }, 205 | "block_loop [clause[,clause]...]": { 206 | "description": "Enables loop blocking for the immediately following nested loops. block_loop enables loop blocking for the nested loops. noblock_loop disables loop blocking for the nested loops.", 207 | "prefix": "#pragma block_loop", 208 | "body": [ 209 | "#pragma block_loop" 210 | ] 211 | }, 212 | "noblock_loop": { 213 | "description": "Disables loop blocking for the immediately following nested loops. block_loop enables loop blocking for the nested loops. noblock_loop disables loop blocking for the nested loops.", 214 | "prefix": "#pragma noblock_loop", 215 | "body": [ 216 | "#pragma noblock_loop" 217 | ] 218 | }, 219 | "code_align(n)": { 220 | "description": "Specifies the byte alignment for a loop", 221 | "prefix": "#pragma code_align", 222 | "body": [ 223 | "#pragma code_align" 224 | ] 225 | }, 226 | "distribute_point": { 227 | "description": "Instructs the compiler to prefer loop distribution at the location indicated.", 228 | "prefix": "#pragma distribute_point", 229 | "body": [ 230 | "#pragma distribute_point" 231 | ] 232 | }, 233 | "inline [recursive]": { 234 | "description": "The inline pragma is a hint to the compiler that the user prefers that the calls in question be inlined, but expects the compiler not to inline them if its heuristics determine that the inlining would be overly aggressive and might slow down the compilation of the source code excessively, create too large of an executable, or degrade performance.", 235 | "prefix": "#pragma inline", 236 | "body": [ 237 | "#pragma inline" 238 | ] 239 | }, 240 | "forceinline [recursive]": { 241 | "description": "The forceinline pragma indicates that the calls in question should be inlined whenever the compiler is capable of doing so.", 242 | "prefix": "#pragma forceinline", 243 | "body": [ 244 | "#pragma forceinline" 245 | ] 246 | }, 247 | "noinline": { 248 | "description": "The noinline pragma indicates that the calls in question should not be inlined.", 249 | "prefix": "#pragma noinline", 250 | "body": [ 251 | "#pragma noinline" 252 | ] 253 | }, 254 | "intel_omp_task [clause[[,]clause]...]": { 255 | "description": "For Intel legacy tasking, specifies a unit of work, potentially executed by a different thread.", 256 | "prefix": "#pragma intel_omp_task", 257 | "body": [ 258 | "#pragma intel_omp_task" 259 | ] 260 | }, 261 | "intel_omp_taskq[clause[[,]clause]...]": { 262 | "description": "For Intel legacy tasking, specifies an environment for the while loop in which to queue the units of work specified by the enclosed task pragma.", 263 | "prefix": "#pragma intel_omp_taskq", 264 | "body": [ 265 | "#pragma intel_omp_taskq" 266 | ] 267 | }, 268 | "loop_count": { 269 | "description": "Specifies the iterations for a for loop.", 270 | "prefix": "#pragma loop_count", 271 | "body": [ 272 | "#pragma loop_count" 273 | ] 274 | }, 275 | "nofusion": { 276 | "description": "Prevents a loop from fusing with adjacent loops.", 277 | "prefix": "#pragma nofusion", 278 | "body": [ 279 | "#pragma nofusion" 280 | ] 281 | }, 282 | "novector": { 283 | "description": "Specifies that a particular loop should never be vectorized.", 284 | "prefix": "#pragma novector", 285 | "body": [ 286 | "#pragma novector" 287 | ] 288 | }, 289 | "omp simd early_exit": { 290 | "description": "Extends #pragma omp simd, allowing vectorization of multiple exit loops.", 291 | "prefix": "#pragma omp simd early_exit", 292 | "body": [ 293 | "#pragma omp simd early_exit" 294 | ] 295 | }, 296 | "optimize('', on|off)": { 297 | "description": "Enables or disables optimizations for code after this pragma until another optimize pragma or end of the translation unit.", 298 | "prefix": "#pragma optimize", 299 | "body": [ 300 | "#pragma optimize" 301 | ] 302 | }, 303 | "optimization_level n": { 304 | "description": "Controls optimization for one function or all functions after its first occurrence.", 305 | "prefix": "#pragma optimization_level", 306 | "body": [ 307 | "#pragma optimization_level" 308 | ] 309 | }, 310 | "optimization_parameter": { 311 | "description": "Passes certain information about a function to the optimizer.", 312 | "prefix": "#pragma intel optimization_parameter", 313 | "body": [ 314 | "#pragma intel optimization_parameter" 315 | ] 316 | }, 317 | "parallel [clause[ [,]clause]...]": { 318 | "description": "Resolves dependencies to facilitate auto-parallelization of the immediately following loop", 319 | "prefix": "#pragma parallel", 320 | "body": [ 321 | "#pragma parallel" 322 | ] 323 | }, 324 | "noparallel": { 325 | "description": "Prevents auto-parallelization of the immediately following loop", 326 | "prefix": "#pragma noparallel", 327 | "body": [ 328 | "#pragma noparallel" 329 | ] 330 | }, 331 | "prefetch": { 332 | "description": "This pragma hints to the compiler to generate data prefetches for some memory references. These hints affect the heuristics used in the compiler. Prefetching data can minimize the effects of memory latency.", 333 | "prefix": "#pragma prefetch", 334 | "body": [ 335 | "#pragma prefetch" 336 | ] 337 | }, 338 | "noprefetch [var1 [, var2]...]": { 339 | "description": "The noprefetch pragma hints to the compiler not to generate data prefetches for some memory references. This affects the heuristics used in the compiler.", 340 | "prefix": "#pragma noprefetch", 341 | "body": [ 342 | "#pragma noprefetch" 343 | ] 344 | }, 345 | "simd [clause[ [,] clause]...]": { 346 | "description": "The simd pragma is used to guide the compiler to vectorize more loops. Vectorization using the simd pragma complements (but does not replace) the fully automatic approach.", 347 | "prefix": "#pragma simd", 348 | "body": [ 349 | "#pragma simd" 350 | ] 351 | }, 352 | "simdoff": { 353 | "description": "Specifies a block of code in the SIMD loop or SIMD-enabled function that should be executed serially, in a logical order of SIMD lanes.", 354 | "prefix": "#pragma simdoff", 355 | "body": [ 356 | "#pragma simdoff" 357 | ] 358 | }, 359 | "unroll(n)": { 360 | "description": "The unroll[n] pragma tells the compiler how many times to unroll a counted loop.", 361 | "prefix": "#pragma unroll", 362 | "body": [ 363 | "#pragma unroll" 364 | ] 365 | }, 366 | "nounroll": { 367 | "description": "The nounroll pragma instructs the compiler not to unroll a specified loop.", 368 | "prefix": "#pragma nounroll", 369 | "body": [ 370 | "#pragma nounroll" 371 | ] 372 | }, 373 | "unroll_and_jam (n)": { 374 | "description": "The unroll_and_jam pragma partially unrolls one or more loops higher in the nest than the innermost loop and fuses/jams the resulting loops back together. This transformation allows more reuses in the loop.", 375 | "prefix": "#pragma unroll_and_jam (n)", 376 | "body": [ 377 | "#pragma unroll_and_jam (n)" 378 | ] 379 | }, 380 | "nounroll_and_jam": { 381 | "description": "When unrolling a loop increases register pressure and code size it may be necessary to prevent unrolling of a nested loop or an imperfect nested loop. In such cases, use the nounroll_and_jam pragma. The nounroll_and_jam pragma hints to the compiler not to unroll a specified loop.", 382 | "prefix": "#pragma nounroll_and_jam", 383 | "body": [ 384 | "#pragma nounroll_and_jam" 385 | ] 386 | }, 387 | "vector": { 388 | "description": "Tells the compiler that the loop should be vectorized according to the argument keywords.", 389 | "prefix": "#pragma vector", 390 | "body": [ 391 | "#pragma vector" 392 | ] 393 | } 394 | } -------------------------------------------------------------------------------- /src/AdvisorLaunchScriptWriter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 'use strict'; 8 | import * as vscode from 'vscode'; 9 | import * as path from 'path'; 10 | import * as fs from 'fs'; 11 | import { LaunchScriptWriter } from './LaunchScriptWriter'; 12 | import { ProjectSettings } from './ProjectSettings'; 13 | import { checkIfPathExist, removeScriptPath } from './utils/utils'; 14 | import messages from './messages'; 15 | 16 | export class AdvisorLaunchScriptWriter extends LaunchScriptWriter { 17 | protected toolname: string = 'advisor'; 18 | 19 | public async updateProjectPath(): Promise { 20 | const scriptPath = await this.getLauncherScriptPath(); 21 | 22 | if (!await checkIfPathExist(scriptPath)) return; 23 | 24 | fs.readFile(scriptPath, 'utf8', async function(err: any, content: any) { 25 | if (err) { 26 | vscode.window.showErrorMessage(messages.errReadScript(scriptPath, err)); 27 | return; 28 | }; 29 | 30 | const projectPath = vscode.workspace.getConfiguration().get('intel-corporation.oneapi-analysis-configurator.advisor.project-folder'); 31 | const normalizedProjectPath = projectPath ? path.normalize(projectPath) : ''; 32 | 33 | if (normalizedProjectPath === '') { 34 | removeScriptPath(scriptPath); 35 | } 36 | const updatedContent = content.replace(/--project-dir "[^"]*"/, `--project-dir "${normalizedProjectPath}"`, 'utf8') 37 | .replace(/advisor-gui "[^"]*"/, `advisor-gui "${normalizedProjectPath}"`, 'utf8'); 38 | 39 | await fs.promises.writeFile(scriptPath, updatedContent, { mode: 0o744 }); 40 | }); 41 | } 42 | 43 | public async updateInstallRoot(): Promise { 44 | const scriptPath = await this.getLauncherScriptPath(); 45 | 46 | if (!await checkIfPathExist(scriptPath)) return; 47 | 48 | const installRoot = vscode.workspace.getConfiguration().get('intel-corporation.oneapi-analysis-configurator.advisor.install-root'); 49 | const normalizedinstallRoot = installRoot ? path.normalize(installRoot) : ''; 50 | const fullPath = path.join(normalizedinstallRoot, 'latest', 'bin64', 'advixe-cl'); 51 | 52 | if (!await checkIfPathExist(fullPath)) { 53 | await removeScriptPath(scriptPath); 54 | return; 55 | }; 56 | 57 | fs.readFile(scriptPath, 'utf8', async function(err: any, content: any) { 58 | if (err) { 59 | vscode.window.showErrorMessage(messages.failedReadScript(scriptPath, err)); 60 | return; 61 | } 62 | 63 | const updatedContent = content.replace(/source "[^"]*"/, `source "${normalizedinstallRoot}"`, 'utf8'); 64 | 65 | await fs.promises.writeFile(scriptPath, updatedContent, { mode: 0o744 }); 66 | }); 67 | } 68 | 69 | public async writeLauncherScript(settings: ProjectSettings): Promise { 70 | const toolInstallFolder = await settings.getToolInstallFolder(); 71 | const toolOutputFolder = settings.getToolOutputFolder(); 72 | const projectBinary = await settings.getProjectBinary(); 73 | 74 | if (!toolInstallFolder || !toolOutputFolder || !projectBinary) { 75 | return; 76 | } 77 | 78 | let command = ''; 79 | 80 | switch (this.osType) { 81 | case 'Linux': 82 | case 'Darwin': 83 | command = `#!/bin/bash\nsource "${toolInstallFolder}/env/vars.sh" && advixe-cl --create-project --project-dir "${toolOutputFolder}" -- "${projectBinary}" && advisor-gui "${toolOutputFolder}/e000"`; 84 | break; 85 | case 'Windows_NT': 86 | command = `@echo off\r\n"${toolInstallFolder}\\env\\vars.bat" && advixe-cl --create-project --project-dir "${toolOutputFolder}" -- "${projectBinary}" && advisor-gui "${toolOutputFolder}\\e000"`; 87 | break; 88 | } 89 | if (command) { 90 | const launchScriptPath = this.whereLauncherScriptPath(settings.getProjectRootNode()); 91 | const parentFolder = path.dirname(launchScriptPath); 92 | 93 | await fs.promises.mkdir(parentFolder, { recursive: true }); 94 | await fs.promises.writeFile(launchScriptPath, command, { mode: 0o744 }); 95 | // vscode.window.showInformationMessage(command); 96 | vscode.commands.executeCommand('workbench.action.tasks.runTask', messages.launchAdvisor); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/LaunchConfigurator.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | 'use strict'; 9 | import * as vscode from 'vscode'; 10 | import { execSync } from 'child_process'; 11 | import { posix, join, parse, normalize } from 'path'; 12 | import { existsSync, writeFileSync } from 'fs'; 13 | import { getPSexecutableName, getworkspaceFolder, isExtensionInstalled, isWorkspaceOpen, propmtToInstallExtension } from './utils/utils'; 14 | import messages from './messages'; 15 | 16 | interface TaskConfigValue { 17 | label: string; 18 | command: string; 19 | type: string; 20 | options: { 21 | cwd: string; 22 | } 23 | } 24 | 25 | interface CppConfiguration { 26 | compilerName: string; 27 | cStandard: string; 28 | cppStandard: string; 29 | compilerPath: string; 30 | compilerArgs: string[]; 31 | includePaths: string[] 32 | } 33 | 34 | export class LaunchConfigurator { 35 | cppConfiguration: CppConfiguration = { 36 | compilerName: '', 37 | cStandard: '', 38 | cppStandard: '', 39 | compilerPath: '', 40 | compilerArgs: [], 41 | includePaths: [] 42 | }; 43 | 44 | async makeTasksFile(): Promise { 45 | const workspaceFolder = await getworkspaceFolder(); 46 | 47 | if (!workspaceFolder) { 48 | return false; // for unit tests 49 | } 50 | const projectRootDir = `${workspaceFolder?.uri.fsPath}`; 51 | let buildSystem = ''; 52 | let makeFileName; 53 | 54 | if (existsSync(`${projectRootDir}/Makefile`)) { 55 | makeFileName = 'Makefile'; 56 | } else if (existsSync(`${projectRootDir}/makefile`)) { 57 | makeFileName = 'makefile'; 58 | } 59 | if (makeFileName) { 60 | if (process.platform === 'win32') { 61 | vscode.window.showInformationMessage('Working with makefile project is not available for Windows.', { modal: true }); 62 | return false; 63 | } 64 | buildSystem = 'make'; 65 | } 66 | if (existsSync(`${projectRootDir}/CMakeLists.txt`)) { 67 | buildSystem = 'cmake'; 68 | } 69 | if (buildSystem === '') { 70 | vscode.window.showErrorMessage(messages.failedGenerateTasks, { modal: true }); 71 | return false; 72 | } 73 | const buildTargets = await this.getTargets(projectRootDir, buildSystem, makeFileName); 74 | let isContinue = true; 75 | const optionsForChoose: vscode.InputBoxOptions = { 76 | placeHolder: messages.chooseTask(buildSystem) 77 | }; 78 | const dialogOptions: string[] = [messages.selectNewTarget, messages.choiceClose]; 79 | const options: vscode.QuickPickOptions = { 80 | placeHolder: messages.createNewTask 81 | }; 82 | 83 | do { 84 | const selection = await vscode.window.showQuickPick(dialogOptions, options); 85 | 86 | if (!selection || selection === messages.choiceClose) { 87 | isContinue = false; 88 | return true; 89 | } 90 | await this.showChooseTaskWindow(buildTargets, optionsForChoose, projectRootDir, buildSystem, makeFileName); 91 | } while (isContinue); 92 | return true; 93 | } 94 | 95 | async showChooseTaskWindow(buildTargets: vscode.QuickPickItem[], options: vscode.InputBoxOptions, projectRootDir: string, buildSystem: string, makeFileName: string | undefined): Promise { 96 | const selection = await vscode.window.showQuickPick(buildTargets, options); 97 | 98 | if (!selection) { 99 | return true; 100 | } 101 | const taskConfig = vscode.workspace.getConfiguration('tasks'); 102 | const taskConfigValue: TaskConfigValue = { 103 | label: selection.label, 104 | command: '', 105 | type: 'shell', 106 | options: { 107 | cwd: `${projectRootDir}`.split(/[\\/]/g).join(posix.sep) 108 | } 109 | }; 110 | 111 | switch (buildSystem) { 112 | case 'make': { 113 | const cmd = `make ${selection.label} -f ${projectRootDir}/${makeFileName}`; 114 | 115 | taskConfigValue.command += cmd; 116 | break; 117 | } 118 | case 'cmake': { 119 | const cmd = process.platform === 'win32' 120 | ? `$val=Test-Path -Path 'build'; if($val -ne $true) {New-Item -ItemType directory -Path 'build'}; cmake -S . -B 'build' -G 'NMake Makefiles'; cd build; nmake ${selection.label}` 121 | : `mkdir -p build && cmake -S . -B build && cmake --build build && cmake --build build --target ${selection.label}`; 122 | 123 | taskConfigValue.command += cmd; 124 | break; 125 | } 126 | default: { 127 | break; 128 | } 129 | } 130 | let config = taskConfig.tasks; 131 | 132 | if (!config) { 133 | config = [taskConfigValue]; 134 | } else { 135 | const isUniq: boolean = await this.checkTaskItem(config, taskConfigValue); 136 | 137 | if (!isUniq) { 138 | vscode.window.showInformationMessage(messages.duplicatedTask(taskConfigValue.label)); 139 | return false; 140 | } 141 | config.push(taskConfigValue); 142 | } 143 | taskConfig.update('tasks', config, false); 144 | vscode.window.showInformationMessage(messages.addedTask(taskConfigValue.label)); 145 | return true; 146 | } 147 | 148 | isOneApiEnvironmentSet(): boolean { 149 | return !!process.env.SETVARS_COMPLETED; 150 | } 151 | 152 | async configureCppProperties(): Promise { 153 | try { 154 | await this.checkPrerequisites(); 155 | await this.requestPropertiesFromUser(); 156 | await this.requestIncludePathsFromCompiler(); 157 | await this.updateCppConfiguration(); 158 | vscode.window.showInformationMessage(messages.configureCppProperties); 159 | } catch (e) { 160 | console.error(e); 161 | if (e instanceof Error) { 162 | vscode.window.showErrorMessage(e.message, { modal: true }); 163 | } 164 | } 165 | } 166 | 167 | private async checkPrerequisites() { 168 | if (!isExtensionInstalled('intel-corporation.oneapi-environment-configurator')) { 169 | propmtToInstallExtension('intel-corporation.oneapi-environment-configurator', messages.installEnvConfigurator); 170 | throw Error(messages.installEnvConfigurator); 171 | } 172 | if (!isExtensionInstalled('ms-vscode.cpptools')) { 173 | propmtToInstallExtension('ms-vscode.cpptools', messages.installCpp); 174 | throw Error(messages.installEnvConfigurator); 175 | } 176 | if (!this.isOneApiEnvironmentSet()) { 177 | throw Error(messages.errOneApiEnvRequired); 178 | } 179 | 180 | if (!isWorkspaceOpen()) { 181 | throw Error(messages.errWorkingDir); 182 | } 183 | } 184 | 185 | async requestPropertiesFromUser() { 186 | const compilers = ['icpx (-fsycl)', 'icpx', 'icc (ia32)', 'icc (intel64)', 'icpc (ia32)', 'icpc (intel64)', 'icx', 'icx (-fsycl)', 'dpcpp']; 187 | const cStandards = ['c17', 'c11', 'c99']; 188 | const cppStarndards = ['c++17', 'c++14']; 189 | 190 | const compiler = await vscode.window.showQuickPick(compilers, { placeHolder: ' compiler', title: 'icpx -fsycl is default' }); 191 | const cStandard = await vscode.window.showQuickPick(cStandards, { title: 'c17 is recommended for C compilation' }); 192 | const cppStandard = await vscode.window.showQuickPick(cppStarndards, { title: 'c++17 is recommended C++ compilation' }); 193 | 194 | if (!compiler || !cppStandard || !cStandard) { 195 | throw Error('Failed to get cpp properties from user'); 196 | } 197 | this.cppConfiguration.cStandard = cStandard; 198 | this.cppConfiguration.cppStandard = cppStandard; 199 | this.cppConfiguration.compilerName = compiler.split(' ')[0]; 200 | this.cppConfiguration.compilerArgs = (compiler.indexOf('-fsycl') >= 0) ? ['-fsycl'] : []; 201 | } 202 | 203 | private async requestIncludePathsFromCompiler() { 204 | this.cppConfiguration.compilerPath = this.getCompilerPath(); 205 | 206 | if (this.cppConfiguration.compilerPath.length === 0) { 207 | throw Error(messages.errCompilerPath); 208 | } 209 | const separator = process.platform === 'win32' ? '\r\n' : '\n'; 210 | const compilerOutput = execSync(`"${this.cppConfiguration.compilerName}" -xc++ -E -P -v -dD -c ${process.platform === 'win32' ? 'NUL' : '/dev/null'} 2>&1`) 211 | .toString().split(separator).map((string) => { return string.trimStart(); }); 212 | const includePaths = compilerOutput.slice(compilerOutput.indexOf('#include <...> search starts here:') + 1, compilerOutput.indexOf('End of search list.')); 213 | 214 | this.cppConfiguration.includePaths = includePaths.map(path => { 215 | return normalize(path); 216 | }); 217 | } 218 | 219 | private getCompilerPath() { 220 | try { 221 | const separator = process.platform === 'win32' ? '\r\n' : '\n'; 222 | const cmd = process.platform === 'win32' ? `where ${this.cppConfiguration.compilerName}` : `which ${this.cppConfiguration.compilerName}`; 223 | const compilerPath = execSync(cmd).toString().split(separator)[0]; 224 | 225 | return compilerPath; 226 | } catch (e) { 227 | return ''; 228 | } 229 | } 230 | 231 | async updateCppConfiguration() { 232 | const workspaceFolder = await getworkspaceFolder(); 233 | 234 | if (!workspaceFolder) { 235 | throw Error('Can not find workspace folder.'); 236 | } 237 | 238 | const cppConfiguration = vscode.workspace.getConfiguration('C_Cpp', workspaceFolder); 239 | 240 | cppConfiguration.update('default.cppStandard', this.cppConfiguration.cppStandard, vscode.ConfigurationTarget.WorkspaceFolder); 241 | cppConfiguration.update('default.includePath', ['${workspaceFolder}/**'].concat(this.cppConfiguration.includePaths), vscode.ConfigurationTarget.WorkspaceFolder); 242 | cppConfiguration.update('default.defines', [], vscode.ConfigurationTarget.WorkspaceFolder); 243 | cppConfiguration.update('default.compilerPath', this.cppConfiguration.compilerPath, vscode.ConfigurationTarget.WorkspaceFolder); 244 | cppConfiguration.update('default.compilerArgs', this.cppConfiguration.compilerArgs, vscode.ConfigurationTarget.WorkspaceFolder); 245 | cppConfiguration.update('default.cStandard', this.cppConfiguration.cStandard, vscode.ConfigurationTarget.WorkspaceFolder); 246 | } 247 | 248 | async quickBuild(isSyclEnabled: boolean): Promise { 249 | if (!this.isOneApiEnvironmentSet()) { 250 | vscode.window.showErrorMessage(messages.errInitEnvVars, { modal: true }); 251 | return false; 252 | } 253 | const textEditor = vscode.window.activeTextEditor; 254 | 255 | if (!textEditor) { 256 | vscode.window.showErrorMessage(messages.errNoOpenFile, { modal: true }); 257 | return false; 258 | } 259 | const document = textEditor.document; 260 | const language = document.languageId; 261 | 262 | if (language !== 'cpp') { 263 | vscode.window.showErrorMessage(messages.errCppFile, { modal: true }); 264 | return false; 265 | } 266 | const parsedPath = parse(document.fileName); 267 | const source = document.fileName; 268 | const dest = join(parsedPath.dir, process.platform === 'win32' ? `${parsedPath.name}.exe` : parsedPath.name); 269 | const cmd = `icpx ${isSyclEnabled ? '-fsycl -fsycl-unnamed-lambda' : ''} "${source}" -o "${dest}" -v`; 270 | 271 | try { 272 | execSync(cmd); 273 | } catch (err: any) { 274 | const logPath = join(parsedPath.dir, 'compile_log'); 275 | 276 | writeFileSync(logPath, err.message); 277 | vscode.window.showErrorMessage(messages.errLog(logPath), { modal: true }); 278 | return false; 279 | } 280 | vscode.window.showInformationMessage(messages.builtFile(dest)); 281 | return true; 282 | } 283 | 284 | private async checkTaskItem(listItems: TaskConfigValue[], newItem: TaskConfigValue): Promise { 285 | if (listItems.length === 0) { 286 | return true; // for tests 287 | } 288 | 289 | const existItem = listItems.find(item => item.label === newItem.label); 290 | const dialogOptions: string[] = [messages.skipTarget, messages.renameTask]; 291 | 292 | if (existItem) { 293 | const options: vscode.InputBoxOptions = { 294 | placeHolder: messages.existedTask(newItem.label) 295 | }; 296 | const selection = await vscode.window.showQuickPick(dialogOptions, options); 297 | 298 | if (!selection || selection === messages.skipTarget) { 299 | return false; 300 | } else { 301 | const inputBoxText: vscode.InputBoxOptions = { 302 | placeHolder: messages.newTaskName 303 | }; 304 | const inputLabel = await vscode.window.showInputBox(inputBoxText); 305 | 306 | if (inputLabel) { 307 | newItem.label = inputLabel; 308 | } 309 | } 310 | } 311 | return true; 312 | } 313 | 314 | private async getTargets(projectRootDir: string, buildSystem: string, makeFileName: string | undefined): Promise { 315 | try { 316 | let targets: string[]; 317 | 318 | switch (buildSystem) { 319 | case 'make': { 320 | targets = execSync( 321 | 'make -pRrq : 2>/dev/null | awk -v RS= -F: \'/^# File/,/^# Finished Make data base/ {if ($1 !~ "^[#.]") {print $1}}\' | egrep -v \'^[^[:alnum:]]\' | sort', 322 | { cwd: projectRootDir }).toString().split('\n'); 323 | targets.pop(); 324 | 325 | const workspaceFolderName = vscode.workspace.workspaceFolders?.find((folder) => projectRootDir.split('/').find((el) => el === folder.name)); 326 | const path = workspaceFolderName ? projectRootDir.slice(projectRootDir.indexOf(workspaceFolderName.name)) : projectRootDir; 327 | 328 | return targets.map((oneTarget) => { 329 | return { 330 | label: oneTarget, 331 | description: `target from ${path}/${makeFileName}` 332 | }; 333 | }); 334 | } 335 | case 'cmake': { 336 | const projectRootDirParced = `"${projectRootDir}"`; 337 | 338 | targets = ['all', 'clean']; 339 | const powerShellExecName = getPSexecutableName(); 340 | const cmd = process.platform === 'win32' 341 | ? `where /r ${projectRootDirParced} CMakeLists.txt` 342 | : `find ${projectRootDirParced} -name 'CMakeLists.txt'`; 343 | const pathsToCmakeLists = execSync(cmd).toString().split('\n'); 344 | const optinosItems: vscode.QuickPickItem[] = []; 345 | 346 | pathsToCmakeLists.pop(); 347 | pathsToCmakeLists.forEach(async(onePath) => { 348 | const normalizedPath = normalize(onePath.replace('\r', '')).split(/[\\/]/g).join(posix.sep); 349 | const workspaceFolderName = vscode.workspace.workspaceFolders?.find((folder) => normalizedPath.split('/').find((el) => el === folder.name)); 350 | const path = workspaceFolderName ? normalizedPath.slice(normalizedPath.indexOf(workspaceFolderName.name)) : normalizedPath; 351 | 352 | const cmd = process.platform === 'win32' 353 | ? `${powerShellExecName} -Command "$targets=(gc ${`"${normalizedPath.replace(/ /g, '` ')}"`}) | Select-String -Pattern '\\s*add_custom_target\\s*\\(\\s*(\\w*)' ; $targets.Matches | ForEach-Object -Process {echo $_.Groups[1].Value} | Select-Object -Unique | ? {$_.trim() -ne '' } "` 354 | : `awk '/^ *add_custom_target/' '${normalizedPath}' | sed -e's/add_custom_target *(/ /; s/\\r/ /' | awk '{print $1}' | uniq`; 355 | 356 | if (powerShellExecName || process.platform !== 'win32') { 357 | targets = targets.concat(execSync(cmd, { cwd: projectRootDir }).toString().split('\n')); 358 | targets.pop(); 359 | } else { 360 | vscode.window.showErrorMessage(messages.errPowerShell); 361 | } 362 | targets.forEach((oneTarget) => { 363 | optinosItems.push({ 364 | label: posix.normalize(oneTarget.replace('\r', '')), 365 | description: `target from ${path}` 366 | }); 367 | }); 368 | }); 369 | return optinosItems; 370 | } 371 | default: { 372 | break; 373 | } 374 | } 375 | return []; 376 | } catch (err) { 377 | vscode.window.showErrorMessage(messages.errGetTargets(err)); 378 | return []; 379 | } 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/LaunchScriptWriter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 'use strict'; 8 | import path = require('path'); 9 | import { ProjectSettings } from './ProjectSettings'; 10 | import * as vscode from 'vscode'; 11 | import { checkExecFile, checkIfPathExist, removeScriptPath } from './utils/utils'; 12 | import { promises, readFile } from 'fs'; 13 | import * as os from 'os'; 14 | import messages from './messages'; 15 | export abstract class LaunchScriptWriter { 16 | protected osType: string = os.type(); 17 | protected projectRoot: string = ''; 18 | protected abstract toolname: string; 19 | 20 | public abstract writeLauncherScript(settings: ProjectSettings): void; 21 | public abstract updateProjectPath(): Promise; 22 | public abstract updateInstallRoot(): Promise; 23 | 24 | protected whereLauncherScriptPath(projRoot?: string): string { 25 | const fileExt = this.osType === 'Windows_NT' ? 'bat' : 'sh'; 26 | 27 | if (projRoot) { 28 | this.projectRoot = projRoot; 29 | } 30 | const launchScriptPath = path.join(this.projectRoot, `launch-${this.toolname}.${fileExt}`).normalize(); 31 | 32 | return launchScriptPath; 33 | }; 34 | 35 | public async getLauncherScriptPath(projRoot?: string): Promise { 36 | const launchScriptPath = this.whereLauncherScriptPath(projRoot); 37 | 38 | if (!await checkIfPathExist(launchScriptPath)) return ''; 39 | return launchScriptPath; 40 | } 41 | 42 | public async updateAppPath(): Promise { 43 | const scriptPath = await this.getLauncherScriptPath(); 44 | const binaryPath = vscode.workspace.getConfiguration().get('intel-corporation.oneapi-analysis-configurator.binary-path'); 45 | const normalizedBinaryPath = binaryPath ? path.normalize(binaryPath) : ''; 46 | 47 | if (!await checkExecFile(normalizedBinaryPath)) { 48 | if (normalizedBinaryPath !== '') { 49 | vscode.window.showErrorMessage(messages.errExecFile(normalizedBinaryPath)); 50 | } 51 | await removeScriptPath(scriptPath); 52 | return; 53 | }; 54 | 55 | if (!await checkIfPathExist(scriptPath)) return; 56 | 57 | readFile(scriptPath, 'utf8', async function(err: any, content: any) { 58 | if (err) { 59 | vscode.window.showErrorMessage(messages.failedReadScript(scriptPath, err)); 60 | return; 61 | } 62 | const updatedContent = content.replace(/--app-path "[^"]*"/, `--app-path "${normalizedBinaryPath}"`, 'utf8'); 63 | 64 | await promises.writeFile(scriptPath, updatedContent, { mode: 0o744 }); 65 | }); 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /src/ProjectSettings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 'use strict'; 8 | import * as vscode from 'vscode'; 9 | import * as path from 'path'; 10 | import { existsSync } from 'fs'; 11 | import { join } from 'path'; 12 | import { checkExecFile, filter } from './utils/utils'; 13 | import messages from './messages'; 14 | const { readdir } = require('fs').promises; 15 | // 16 | // This class prompts the user for the binary to be profiled, 17 | // the profiler install location, and the profiler output directory. 18 | // It then caches these settings in the local .vscode/settings.json and 19 | // re-loads them on subsequent invocations so that the user is not prompted. 20 | // 21 | 22 | export class ProjectSettings { 23 | private projectRoot: vscode.Uri | undefined; 24 | private projectBinary: string; 25 | private toolName: string; 26 | private toolDisplayName: string; 27 | private toolInstallFolder: string; 28 | private toolOutputFolder: string; 29 | 30 | // Initialize member variables. 31 | // tool - The short name for the tool (advisor/vtune) that can be used in file path construction. 32 | // toolName - The display name™ of the tool used when prompting the user for information. 33 | // rootNode - the root node of the selected item in the VS Code Explorer, used to find the root path 34 | // of the currently open folder or workspace. 35 | public constructor(tool: string, toolName: string, rootNode: vscode.Uri | undefined) { 36 | // Project-specific values. 37 | this.projectRoot = rootNode; 38 | this.projectBinary = ''; 39 | 40 | // Tool-specific values. 41 | this.toolName = tool; 42 | this.toolDisplayName = toolName; 43 | this.toolInstallFolder = ''; 44 | this.toolOutputFolder = ''; 45 | } 46 | 47 | public async getProjectSettings(): Promise { 48 | if (!this.getProjectRootNode()) { 49 | await this.promptForProjectRootNode(); 50 | if (!this.getProjectRootNode()) { 51 | return false; 52 | } 53 | } 54 | const binaryFromSettings = await this.getProjectBinary(); 55 | 56 | if (!await this.promptForProjectBinary(binaryFromSettings)) { 57 | return false; 58 | } 59 | 60 | if (await this.getToolInstallFolder() === '') { 61 | return false; 62 | } 63 | 64 | if (!this.getToolOutputFolder()) { 65 | return await this.promptForToolOutputFolder(); 66 | } 67 | return true; 68 | } 69 | 70 | // Get the path of the executable to be profiled. 71 | public async getProjectBinary(): Promise { 72 | if (!this.projectBinary && this.projectRoot) { 73 | const binaryPath : string = vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator', this.projectRoot).get('binary-path') || ''; 74 | const normalizedBinaryPath = binaryPath ? path.normalize(binaryPath) : ''; 75 | 76 | if (!await checkExecFile(normalizedBinaryPath)) return ''; 77 | this.projectBinary = normalizedBinaryPath; 78 | } 79 | return this.projectBinary; 80 | } 81 | 82 | private async getFiles(dir: string): Promise { 83 | const dirents = await readdir(dir, { withFileTypes: true }); 84 | const files = await Promise.all(dirents.map((dirent: any) => { 85 | const res = path.resolve(dir, dirent.name); 86 | 87 | return dirent.isDirectory() ? this.getFiles(res) : res; 88 | })); 89 | 90 | return await filter(Array.prototype.concat(...files), async(val: string) => { 91 | const isExec = await checkExecFile(val); 92 | 93 | return isExec; 94 | }); 95 | } 96 | 97 | // Prompt the user to browse to the executable to be profiled. 98 | public async promptForProjectBinary(binaryFromSettings?: string): Promise { 99 | const workspaceFolder = this.projectRoot; 100 | 101 | if (!workspaceFolder) { 102 | return false; 103 | } 104 | const projectRootDir = `${workspaceFolder?.fsPath}`; 105 | 106 | const files = await this.getFiles(projectRootDir); 107 | 108 | if (binaryFromSettings && files.indexOf(binaryFromSettings) === -1) { 109 | files.push(binaryFromSettings); 110 | } 111 | const options: vscode.InputBoxOptions = { 112 | title: messages.chooseExec 113 | }; 114 | let dialogList = [messages.changeBinary, messages.openSettings, messages.choiceExit]; 115 | 116 | if (binaryFromSettings) { 117 | dialogList = [binaryFromSettings].concat(dialogList); 118 | } 119 | const selection = await vscode.window.showQuickPick(dialogList, options); 120 | 121 | if (!selection || selection === messages.choiceExit) { 122 | return false; 123 | } 124 | 125 | if (selection === binaryFromSettings) { 126 | return true; 127 | } 128 | 129 | if (selection === messages.openSettings) { 130 | await vscode.commands.executeCommand('workbench.action.openSettings', '@ext:intel-corporation.oneapi-analysis-configurator'); 131 | return false; 132 | } else if (selection === messages.changeBinary) { 133 | const options: vscode.InputBoxOptions = { 134 | title: messages.chooseExecFile 135 | }; 136 | 137 | if (files.length === 0) { 138 | vscode.window.showErrorMessage(messages.couldNotFindExec); 139 | return false; 140 | }; 141 | 142 | const executableUri = await vscode.window.showQuickPick(files, options); 143 | 144 | if (!executableUri) { 145 | return false; 146 | } 147 | 148 | const execFilePath = path.normalize(executableUri); 149 | 150 | this.projectBinary = execFilePath; 151 | if (this.projectRoot) { 152 | if (!path.isAbsolute(this.projectBinary)) { 153 | this.projectBinary = path.join(this.projectRoot.fsPath, this.projectBinary); 154 | } 155 | const selection = await vscode.window.showQuickPick([messages.choiceSave, messages.choiceOnce], { title: messages.saveFilePath }); 156 | 157 | if (selection === messages.choiceSave) { 158 | vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator', this.projectRoot).update('binary-path', this.projectBinary, vscode.ConfigurationTarget.WorkspaceFolder); 159 | } 160 | if (!selection) { 161 | return false; 162 | } 163 | } 164 | } 165 | return true; 166 | } 167 | 168 | // Get the install directory of the profiler. 169 | public async getToolInstallFolder(): Promise { 170 | const execName = this.toolName === 'advisor' ? 'advixe-cl' : 'amplxe-cl'; 171 | 172 | if (!this.toolInstallFolder) { 173 | // 1. check settings.json 174 | this.toolInstallFolder = vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator').get(this.toolName + '.install-root') || ''; 175 | if (this.toolInstallFolder && this.toolInstallFolder !== '' && existsSync(join(this.toolInstallFolder, 'bin64', `${execName}${process.platform === 'win32' ? '.exe' : ''}`))) { 176 | return this.toolInstallFolder; 177 | } else { 178 | const options: vscode.InputBoxOptions = { 179 | title: messages.couldNotFindPath(this.toolName, this.toolInstallFolder) 180 | }; 181 | 182 | const dialogList = [messages.autoSearch(this.toolName), messages.openSettings, messages.choiceExit]; 183 | 184 | const selection = await vscode.window.showQuickPick(dialogList, options); 185 | 186 | if (selection === messages.openSettings) { 187 | await vscode.commands.executeCommand('workbench.action.openSettings', '@ext:intel-corporation.oneapi-analysis-configurator install-root'); 188 | return ''; 189 | } else 190 | if (!selection || selection === messages.choiceExit) return ''; 191 | } 192 | } else { 193 | return this.toolInstallFolder; 194 | } 195 | 196 | // 2.check in $ONEAPI_ROOT new path 197 | if (process.env.ONEAPI_ROOT && existsSync(join(process.env.ONEAPI_ROOT, 'bin', `${execName}${process.platform === 'win32' ? '.exe' : ''}`))) { 198 | this.toolInstallFolder = join(process.env.ONEAPI_ROOT, this.toolName, 'latest'); 199 | await this.promptSaveInstallRootSetting(messages.saveToolPath(this.toolName), 'install-root'); 200 | return this.toolInstallFolder; 201 | } 202 | // check in $ONEAPI_ROOT old path 203 | if (process.env.ONEAPI_ROOT && existsSync(join(process.env.ONEAPI_ROOT, this.toolName, 'latest', 'bin64', `${execName}${process.platform === 'win32' ? '.exe' : ''}`))) { 204 | this.toolInstallFolder = join(process.env.ONEAPI_ROOT, this.toolName, 'latest'); 205 | await this.promptSaveInstallRootSetting(messages.saveToolPath(this.toolName), 'install-root'); 206 | return this.toolInstallFolder; 207 | } 208 | 209 | vscode.window.showErrorMessage(messages.couldNotFind(this.toolName)); 210 | return ''; 211 | } 212 | 213 | // Get the path of the output directory of the profiler. 214 | public getToolOutputFolder(): string { 215 | if (!this.toolOutputFolder && this.projectRoot) { 216 | this.toolOutputFolder = vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator', this.projectRoot).get(this.toolName + '.project-folder') || ''; 217 | } 218 | return this.toolOutputFolder; 219 | } 220 | 221 | // Prompt the user to provide the output directory of the profiler. 222 | public async promptForToolOutputFolder(): Promise { 223 | const toolProjectPath: string | undefined = await vscode.window.showInputBox({ 224 | prompt: messages.specifyPrFolder, 225 | value: './' + this.toolName // default to a subfolder of the folderRoot e.g ./vtune or ./advisor 226 | }); 227 | 228 | if (toolProjectPath) { 229 | this.toolOutputFolder = toolProjectPath; 230 | if (this.projectRoot) { 231 | if (!path.isAbsolute(this.toolOutputFolder)) { 232 | this.toolOutputFolder = path.join(this.projectRoot.fsPath, this.toolOutputFolder); 233 | } 234 | } 235 | await this.promptSaveProjectFolderSetting(messages.saveProjPath, 'project-folder'); 236 | return true; 237 | } 238 | return false; 239 | } 240 | 241 | // WIP - The RootNode methods exist for the sole case of the extension being run 242 | // without a folder or workspace open. There's no cache logic here since there 243 | // won't be a .vscode/settings.json from which to read or write. 244 | public getProjectRootNode(): string { 245 | return (this.projectRoot) ? this.projectRoot.fsPath : ''; 246 | } 247 | 248 | public async promptForProjectRootNode(): Promise { 249 | if (!this.projectRoot) { 250 | if (vscode.workspace.workspaceFolders === undefined) { 251 | vscode.window.showErrorMessage(messages.errWorkingDir, { modal: true }); 252 | vscode.window.showInformationMessage(messages.addWorkingDir); 253 | return; 254 | } 255 | await vscode.window.showWorkspaceFolderPick().then((selection) => { 256 | if (selection === undefined) { 257 | return undefined; 258 | } 259 | this.projectRoot = selection.uri; 260 | }); 261 | } 262 | } 263 | 264 | public async promptSaveInstallRootSetting(message : string, setting : string): Promise { 265 | const options: vscode.InputBoxOptions = { 266 | title: message 267 | }; 268 | const dialogList = [messages.choiceSave, messages.choiceOnce]; 269 | 270 | const selection = await vscode.window.showQuickPick(dialogList, options); 271 | 272 | if (selection === messages.choiceSave) { 273 | await vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator').update(`${this.toolName}.${setting}`, this.toolInstallFolder); 274 | } 275 | } 276 | 277 | public async promptSaveProjectFolderSetting(message : string, setting : string): Promise { 278 | const options: vscode.InputBoxOptions = { 279 | title: message 280 | }; 281 | const dialogList = [messages.choiceSave, messages.choiceOnce]; 282 | 283 | const selection = await vscode.window.showQuickPick(dialogList, options); 284 | 285 | if (selection === messages.choiceSave) { 286 | await vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator').update(`${this.toolName}.${setting}`, this.toolOutputFolder); 287 | } 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /src/VtuneLaunchScriptWriter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 'use strict'; 8 | import * as vscode from 'vscode'; 9 | import * as path from 'path'; 10 | import * as fs from 'fs'; 11 | import { LaunchScriptWriter } from './LaunchScriptWriter'; 12 | import { ProjectSettings } from './ProjectSettings'; 13 | import { checkIfPathExist, checkExecFile, removeScriptPath } from './utils/utils'; 14 | import messages from './messages'; 15 | 16 | export class VtuneLaunchScriptWriter extends LaunchScriptWriter { 17 | protected toolname: string = 'vtune'; 18 | 19 | public async updateProjectPath(): Promise { 20 | const scriptPath = await this.getLauncherScriptPath(); 21 | 22 | if (!await checkIfPathExist(scriptPath)) return; 23 | 24 | fs.readFile(scriptPath, 'utf8', async function(err: any, content: any) { 25 | if (err) { 26 | vscode.window.showErrorMessage(messages.failedReadScript(scriptPath, err)); 27 | return; 28 | } 29 | 30 | const projectPath = vscode.workspace.getConfiguration().get('intel-corporation.oneapi-analysis-configurator.vtune.project-folder'); 31 | const normalizedProjectPath = projectPath ? path.normalize(projectPath) : ''; 32 | 33 | if (normalizedProjectPath === '') { 34 | removeScriptPath(scriptPath); 35 | } 36 | const updatedContent = content.replace(/--project-dir "[^"]*"/, `--project-dir "${normalizedProjectPath}"`, 'utf8'); 37 | 38 | await fs.promises.writeFile(scriptPath, updatedContent, { mode: 0o744 }); 39 | }); 40 | } 41 | 42 | public async updateInstallRoot(): Promise { 43 | const scriptPath = await this.getLauncherScriptPath(); 44 | 45 | if (!await checkIfPathExist(scriptPath)) return; 46 | 47 | const installRoot = vscode.workspace.getConfiguration().get('intel-corporation.oneapi-analysis-configurator.vtune.install-root'); 48 | const normalizedinstallRoot = installRoot ? path.normalize(installRoot) : ''; 49 | const fullPath = path.join(normalizedinstallRoot, 'latest', 'bin64', 'amplxe-cl'); 50 | 51 | if (!await checkExecFile(fullPath)) { 52 | vscode.window.showErrorMessage(messages.errExecFile(fullPath)); 53 | await removeScriptPath(scriptPath); 54 | return; 55 | }; 56 | 57 | fs.readFile(scriptPath, 'utf8', async function(err: any, content: any) { 58 | if (err) { 59 | vscode.window.showErrorMessage(messages.failedReadScript(scriptPath, err)); 60 | return; 61 | } 62 | 63 | const updatedContent = content.replace(/--app-path "[^"]*"/, `--app-path "${normalizedinstallRoot}"`, 'utf8'); 64 | 65 | await fs.promises.writeFile(scriptPath, updatedContent, { mode: 0o744 }); 66 | }); 67 | } 68 | 69 | public async writeLauncherScript(settings: ProjectSettings): Promise { 70 | const toolInstallFolder = await settings.getToolInstallFolder(); 71 | const toolOutputFolder = settings.getToolOutputFolder(); 72 | const projectBinary = await settings.getProjectBinary(); 73 | 74 | if (!toolInstallFolder || !toolOutputFolder || !projectBinary) { 75 | return; 76 | } 77 | 78 | let command = ''; 79 | 80 | switch (this.osType) { 81 | case 'Linux': 82 | case 'Darwin': 83 | command = `#!/bin/bash\nsource "${toolInstallFolder}/env/vars.sh" && vtune-gui --project-path "${toolOutputFolder}"`; 84 | break; 85 | case 'Windows_NT': 86 | command = `@echo off\r\n"${toolInstallFolder}\\env\\vars.bat" && vtune-gui --project-path "${toolOutputFolder}"`; 87 | break; 88 | } 89 | // DEV1A-431: Do not add the --app-path parameter if vtune.vtuneproj exists and 90 | // contains the tag for the project binary. Note that opening the binary in VTune 91 | // without profiling it won't save the project binary path in vtune.vtuneproj. 92 | try { 93 | const contents = await fs.promises.readFile(path.join(toolOutputFolder, 'vtune.vtuneproj'), 'utf8'); 94 | 95 | if (!contents.includes(`${projectBinary}`)) { 96 | command += ` --app-path "${projectBinary}"`; 97 | } 98 | } catch { // The vtune.vtuneproj file does not exist. 99 | command += ` --app-path "${projectBinary}"`; 100 | } 101 | 102 | if (command) { 103 | const launchScriptPath = this.whereLauncherScriptPath(settings.getProjectRootNode()); 104 | const parentFolder = path.dirname(launchScriptPath); 105 | 106 | await fs.promises.mkdir(parentFolder, { recursive: true }); 107 | await fs.promises.writeFile(launchScriptPath, command, { mode: 0o744 }); 108 | // vscode.window.showInformationMessage(command); 109 | vscode.commands.executeCommand('workbench.action.tasks.runTask', messages.launchVTune); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 'use strict'; 8 | import * as vscode from 'vscode'; 9 | import * as os from 'os'; 10 | import { ProjectSettings } from './ProjectSettings'; 11 | import { AdvisorLaunchScriptWriter } from './AdvisorLaunchScriptWriter'; 12 | import { VtuneLaunchScriptWriter } from './VtuneLaunchScriptWriter'; 13 | import { LaunchConfigurator } from './LaunchConfigurator'; 14 | import FPGAMemoryHoverProvider from './hoverProvider'; 15 | import { cpuAttributesTooltips } from './utils/CPUAttributes'; 16 | import messages from './messages'; 17 | import { getBaseUri, updateAnalyzersRoot, wait } from './utils/utils'; 18 | 19 | const fs = require('fs'); 20 | const path = require('path'); 21 | const xml2js = require('xml2js'); 22 | const readFile = fs.promises.readFile; 23 | let advisorProjRoot = ''; 24 | let vtuneProjRoot = ''; 25 | 26 | // eslint-disable-next-line no-unused-vars 27 | enum ExtensionState { 28 | // eslint-disable-next-line no-unused-vars 29 | deprecated, 30 | // eslint-disable-next-line no-unused-vars 31 | actual, 32 | } 33 | // This feature will help to avoid conflicts with deprecated versions of extensions. 34 | // If an deprecated version is found, the user will be given the opportunity to uninstal it. 35 | function checkExtensionsConflict(id: string) { 36 | const ExtensionsList = [['intel-corporation.oneapi-environment-variables', 'intel-corporation.oneapi-environment-configurator'], 37 | ['intel-corporation.oneapi-launch-configurator', 'intel-corporation.oneapi-analysis-configurator'], 38 | ['', 'intel-corporation.oneapi-gdb-debug']]; 39 | 40 | ExtensionsList.forEach((Extension) => { 41 | const actualExtension = vscode.extensions.getExtension(Extension[ExtensionState.actual]); 42 | const deprecatedExtension = vscode.extensions.getExtension(Extension[ExtensionState.deprecated]); 43 | 44 | if (actualExtension?.id === id) { 45 | if (deprecatedExtension) { 46 | const deprExtName = deprecatedExtension.packageJSON.displayName; 47 | const actualExtName = actualExtension.packageJSON.displayName; 48 | 49 | vscode.window.showInformationMessage(messages.deprecatedExtension(deprExtName, actualExtName), messages.goToUninstall, messages.choiceIgnore) 50 | .then((selection) => { 51 | if (selection === messages.goToUninstall) { 52 | vscode.commands.executeCommand('workbench.extensions.uninstallExtension', deprecatedExtension.id).then(function() { 53 | vscode.window.showInformationMessage(messages.completedUninstalling(deprExtName), messages.choiceReload) 54 | .then((selection) => { 55 | if (selection === messages.choiceReload) { vscode.commands.executeCommand('workbench.action.reloadWindow'); } 56 | }); 57 | }); 58 | } 59 | }); 60 | } 61 | } 62 | }); 63 | } 64 | 65 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 66 | export function activate(context: vscode.ExtensionContext): void { 67 | // Todo: The extension is currently activated at startup, as activationEvents in package.json uses '*'. 68 | // Find the viewID for explorer so it could be activated via 'onView:viewId'. 69 | 70 | const parser = new xml2js.Parser(); 71 | let fpgaMemoryAttributes: any = {}; 72 | 73 | readFile(path.join(__dirname, '/../attributes/kernel.xml')).then((data: any) => { 74 | parser.parseStringPromise(data).then((result: any) => { 75 | const attributes = result.reference.refbody[0].table[0].tgroup[0].tbody[0].row; 76 | 77 | for (const att of attributes) { 78 | const name = att.entry[0].codeph[0].replace(/\(.*\)/, '').replace(/[[\]']+/g, '').replace('intel::', '').replace(/\r\n/g, '').trim(); 79 | const description = `${(att.entry[1]._ || att.entry[1].p[0])?.replace(/\s+/g, ' ')}\n\n${messages.kernelAttrLearnMore}`; 80 | 81 | fpgaMemoryAttributes[name] = { 82 | description, 83 | signature: att.entry[0].codeph[0].replace(/[[\]']+/g, '').replace(/\r\n/g, '').trim() 84 | }; 85 | } 86 | }); 87 | }).then(() => { 88 | readFile(path.join(__dirname, '/../attributes/loop.xml')).then((data: any) => { 89 | parser.parseStringPromise(data).then((result: any) => { 90 | console.log('result', result); 91 | const attributes = result.concept.conbody[0].table[0].tgroup[0].tbody[0].row; 92 | 93 | for (const att of attributes) { 94 | const name = att.entry[0].codeph[0].replace(/\(.*\)/, '').replace(/[[\]']+/g, '').replace('intel::', '').replace(/\r\n/g, '').trim(); 95 | const description = `${(att.entry[1]._ || att.entry[1].p[0]._ || att.entry[1].p[0])?.replace(/\s+/g, ' ')}\n\n${messages.loopAttrLearnMore}`; 96 | 97 | fpgaMemoryAttributes[name] = { 98 | description, 99 | signature: att.entry[0].codeph[0].replace(/[[\]']+/g, '').replace(/\r\n/g, '').trim() 100 | }; 101 | } 102 | }); 103 | }); 104 | }).then(() => { 105 | readFile(path.join(__dirname, '/../attributes/memory.xml')).then((data: any) => { 106 | parser.parseStringPromise(data).then((result: any) => { 107 | const attributes = result.concept.conbody[0].table[0].tgroup[0].tbody[0].row; 108 | 109 | for (const att of attributes) { 110 | const name = att.entry[0].codeph[0].replace(/\(.*\)/, '').replace(/[[\]']+/g, '').replace('intel::', '').replace(/\r\n/g, '').trim(); 111 | const description = `${(att.entry[1]._ || att.entry[1].p[0])?.replace(/\s+/g, ' ')}\n\n${messages.memoryAttrLearnMore}`; 112 | 113 | fpgaMemoryAttributes[name] = { 114 | description, 115 | signature: att.entry[0].codeph[0].replace(/[[\]']+/g, '').replace(/\r\n/g, '').trim() 116 | }; 117 | } 118 | }); 119 | fpgaMemoryAttributes.unroll = { 120 | description: messages.unrollAttrDescr, 121 | signature: messages.unrollAttrSignature 122 | }; 123 | fpgaMemoryAttributes = { ...fpgaMemoryAttributes, ...cpuAttributesTooltips }; 124 | context.subscriptions.push(vscode.languages.registerHoverProvider('cpp', new FPGAMemoryHoverProvider(fpgaMemoryAttributes))); 125 | }); 126 | }); 127 | 128 | // Checking for outdated versions of extensions in the VS Code environment 129 | checkExtensionsConflict(context.extension.id); 130 | 131 | // Register the commands that will interact with the user and write the launcher scripts. 132 | vscode.commands.registerCommand('intel-corporation.oneapi-analysis-configurator.launchAdvisor', async(selectedNode: vscode.Uri) => { 133 | // VS Code will return undefined for remoteName if working with a local workspace 134 | if (typeof vscode.env.remoteName !== 'undefined') { 135 | vscode.window.showWarningMessage(messages.warnLaunchingAdvisor); 136 | return; 137 | } 138 | 139 | const settings = new ProjectSettings('advisor', 'Intel® Advisor', getBaseUri(selectedNode)); 140 | 141 | if (await settings.getProjectSettings() === false) { 142 | return; 143 | } 144 | 145 | const writer = new AdvisorLaunchScriptWriter(); 146 | 147 | await writer.writeLauncherScript(settings); 148 | advisorProjRoot = settings.getProjectRootNode(); 149 | }); 150 | vscode.commands.registerCommand('intel-corporation.oneapi-analysis-configurator.launchVTune', async(selectedNode: vscode.Uri) => { 151 | // VS Code will return undefined for remoteName if working with a local workspace 152 | if (typeof vscode.env.remoteName !== 'undefined') { 153 | vscode.window.showWarningMessage(messages.warnLaunchingVTune); 154 | return; 155 | } 156 | 157 | let vtuneName = 'vtune'; 158 | 159 | if (os.type() === 'Darwin') { 160 | // On MacOS, the vtune tool is installed in a different folder. 161 | vtuneName = 'vtune_profiler'; 162 | } 163 | const settings = new ProjectSettings(vtuneName, 'Intel® VTune™ Profiler', getBaseUri(selectedNode)); 164 | 165 | if ((await settings.getProjectSettings() === false)) { 166 | return; 167 | } 168 | 169 | const writer = new VtuneLaunchScriptWriter(); 170 | 171 | await writer.writeLauncherScript(settings); 172 | vtuneProjRoot = settings.getProjectRootNode(); 173 | }); 174 | 175 | // Updating parameters when they are changed in Setting.json 176 | context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async e => { 177 | const vtuneScriptUpdater = new VtuneLaunchScriptWriter(); 178 | const advisorScriptUpdater = new AdvisorLaunchScriptWriter(); 179 | 180 | if (e.affectsConfiguration('intel-corporation.oneapi-analysis-configurator.binary-path')) { 181 | await vtuneScriptUpdater.updateAppPath(); 182 | await advisorScriptUpdater.updateAppPath(); 183 | vscode.window.showInformationMessage(messages.updateBinaryPath); 184 | } 185 | 186 | if (e.affectsConfiguration('intel-corporation.oneapi-analysis-configurator.advisor.install-root')) { 187 | await advisorScriptUpdater.updateInstallRoot(); 188 | vscode.window.showInformationMessage(messages.updateAdvisorInstallRoot); 189 | } 190 | 191 | if (e.affectsConfiguration('intel-corporation.oneapi-analysis-configurator.advisor.project-folder')) { 192 | await advisorScriptUpdater.updateProjectPath(); 193 | vscode.window.showInformationMessage(messages.updateAdvisorProjectFolder); 194 | } 195 | 196 | if (e.affectsConfiguration('intel-corporation.oneapi-analysis-configurator.vtune.install-root')) { 197 | await vtuneScriptUpdater.updateInstallRoot(); 198 | vscode.window.showInformationMessage(messages.updateVtuneInstallRoot); 199 | } 200 | 201 | if (e.affectsConfiguration('intel-corporation.oneapi-analysis-configurator.vtune.project-folder')) { 202 | await vtuneScriptUpdater.updateProjectPath(); 203 | vscode.window.showInformationMessage(messages.updateVtuneProjectFolder); 204 | } 205 | 206 | if (e.affectsConfiguration('intel-corporation.oneapi-analysis-configurator.ONEAPI_ROOT')) { 207 | await wait(5000); 208 | const ONEAPI_ROOT = vscode.workspace.getConfiguration().get('intel-corporation.oneapi-analysis-configurator.ONEAPI_ROOT'); 209 | 210 | if (!ONEAPI_ROOT) return; 211 | const normalizedOneAPIRoot = path.normalize(ONEAPI_ROOT); 212 | 213 | updateAnalyzersRoot(normalizedOneAPIRoot); 214 | vscode.window.showInformationMessage(messages.updateOneApiRoot); 215 | } 216 | })); 217 | 218 | // Register the tasks that will invoke the launcher scripts. 219 | const type = 'toolProvider'; 220 | 221 | vscode.tasks.registerTaskProvider(type, { 222 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 223 | async provideTasks(token?: vscode.CancellationToken) { 224 | const vtune = new VtuneLaunchScriptWriter(); 225 | const vtunerShell = await vtune.getLauncherScriptPath(vtuneProjRoot); 226 | const advisor = new AdvisorLaunchScriptWriter(); 227 | const advisorShell = await advisor.getLauncherScriptPath(advisorProjRoot); 228 | 229 | return [ 230 | new vscode.Task({ type }, vscode.TaskScope.Workspace, 231 | 'Launch Advisor', 'Intel® oneAPI', new vscode.ProcessExecution(advisorShell)), 232 | new vscode.Task({ type }, vscode.TaskScope.Workspace, 233 | 'Launch VTune Profiler', 'Intel® oneAPI', new vscode.ProcessExecution(vtunerShell)) 234 | ]; 235 | }, 236 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 237 | resolveTask(task: vscode.Task, token?: vscode.CancellationToken) { 238 | return task; 239 | } 240 | }); 241 | 242 | const launchConfigurator = new LaunchConfigurator(); 243 | 244 | context.subscriptions.push(vscode.commands.registerCommand('intel-corporation.oneapi-analysis-configurator.generateTaskJson', () => launchConfigurator.makeTasksFile())); 245 | context.subscriptions.push(vscode.commands.registerCommand('intel-corporation.oneapi-analysis-configurator.quickBuild', () => launchConfigurator.quickBuild(false))); 246 | context.subscriptions.push(vscode.commands.registerCommand('intel-corporation.oneapi-analysis-configurator.quickBuildSycl', () => launchConfigurator.quickBuild(true))); 247 | context.subscriptions.push(vscode.commands.registerCommand('intel-corporation.oneapi-analysis-configurator.configureCppProperties', () => launchConfigurator.configureCppProperties())); 248 | } 249 | -------------------------------------------------------------------------------- /src/hoverProvider.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 'use strict'; 8 | import { HoverProvider, Hover, TextDocument, CancellationToken, Position } from 'vscode'; 9 | 10 | export default class FPGAMemoryHoverProvider implements HoverProvider { 11 | private attributes: any; 12 | constructor(attributes: any[]) { 13 | this.attributes = attributes; 14 | } 15 | 16 | public provideHover(document: TextDocument, position: Position, token?: CancellationToken): Hover|undefined { 17 | const wordRange = document.getWordRangeAtPosition(position); 18 | 19 | if (!wordRange) { 20 | return; 21 | } 22 | 23 | const attributeName = document.getText(wordRange); 24 | 25 | const entry = this.attributes[attributeName]; 26 | 27 | if (entry && entry.description) { 28 | const signature = entry.signature || ''; 29 | const contents = [entry.description, { language: 'cpp', value: signature }]; 30 | 31 | return new Hover(contents, wordRange); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/messages.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | deprecatedExtension: (deprExtName: string, actualExtName: string) => { return `${deprExtName} is a deprecated version of the ${actualExtName}. This may lead to the unavailability of overlapping functions.`; }, 3 | goToUninstall: 'Uninstall deprecated', 4 | choiceIgnore: 'Ignore', 5 | choiceReload: 'Reload', 6 | autoSearch: (toolName: string) => { return `Find ${toolName}`; }, 7 | completedUninstalling: (deprExtName: string) => { return `Completed uninstalling the ${deprExtName} extension. Please reload Visual Studio Code.`; }, 8 | updateSettingJson: (folderName: string) => { return `Should this ONEAPI_ROOT update change the setting.json file in the ${folderName} folder?`; }, 9 | choiceUpdate: 'Update', 10 | choiceSkip: 'Skip', 11 | updateVuneRoot: 'Should this ONEAPI_ROOT update change the root path to VTune?', 12 | vtuneRootWasUpdated: 'VTune root path was updated', 13 | updateAdvisorRoot: 'Should this ONEAPI_ROOT update change the root path to Advisor?', 14 | advisorRootWasUpdated: 'Advisor root path was updated', 15 | kernelAttrLearnMore: '[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-fpga-optimization-guide/top/quick-reference/fpga-kernel-attributes.html)', 16 | loopAttrLearnMore: '[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-fpga-optimization-guide/top/quick-reference/fpga-loop-directives.html)', 17 | memoryAttrLearnMore: '[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-fpga-optimization-guide/top/quick-reference/fpga-memory-attributes.html)', 18 | unrollAttrDescr: 'Unrolls a loop in the kernel code.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-fpga-optimization-guide/top/quick-reference/fpga-loop-directives.html)', 19 | unrollAttrSignature: '#pragma unroll N', 20 | warnLaunchingAdvisor: 'Launching Intel Advisor on a remote connection is not currently supported.', 21 | warnLaunchingVTune: 'Launching Intel VTune Profiler on a remote connection is not currently supported.', 22 | updateBinaryPath: 'Binary path was updated. It will change VTune and Advisor app path.', 23 | updateAdvisorInstallRoot: 'Advisor install root was updated.', 24 | updateAdvisorProjectFolder: 'Advisor project folder was updated.', 25 | updateVtuneInstallRoot: 'VTune install root was updated.', 26 | updateVtuneProjectFolder: 'VTune project folder was updated.', 27 | updateOneApiRoot: 'ONEAPI_ROOT was updated. It will update settings.json file from your .vscode folder and may update VTune & Advisor root paths', 28 | choiceInstall: 'Install', 29 | installEnvConfigurator: 'The Environment Configurator for Intel Software Developer Tools is required to configure your oneAPI C/++ projects. Please install it', 30 | installCpp: 'No extension for C/C++ was found. Please install it to configure your oneAPI C/++ projects.', 31 | failedGenerateTasks: 'Generating tasks failed. The project does not contain CMakeLists.txt or MakeFile. Add one of those files to your working directory and try again.', 32 | chooseTask: (buildSystem: string) => `Choose target from ${buildSystem} or push ESC to exit.`, 33 | selectNewTarget: 'Select a new target', 34 | choiceClose: 'Close', 35 | createNewTask: 'Do you want to create a new task?', 36 | duplicatedTask: (label: string) => `Task for "${label}" was skipped as duplicate.`, 37 | addedTask: (label: string) => `Task for "${label}" was added.`, 38 | specifyOneApi: 'Specify the path to your oneAPI installation. Open settings and search for "oneapi-analysis-configurator: ONEAPI_ROOT". Add the absolute path to your installation', 39 | openSettings: 'Open settings', 40 | configureCppProperties: 'C++ properties are successfully edited. Please check .vscode/settings.json for more details.', 41 | oneApiFromConfigurator: 'ONEAPI_ROOT is taken from your Analysis Configurator extension\'s settings', 42 | oneApiFromProcEnv: 'ONEAPI_ROOT is taken from your process environment variables', 43 | oneApiFromEnvConf: 'ONEAPI_ROOT is taken from your Environment Configurator extension\'s settings', 44 | editCppProperties: 'C++ properties are successfully edited. Please check .vscode/settings.json for more details.', 45 | provideCppIncludeFiles: 'Please provide your additional cpp include files in .vscode/settings.json or in C++ extension settings.', 46 | errOneApiEnvRequired: 'oneAPI environment is required. Press Ctrl+Shift+P and execute "Intel oneAPI: Initialize environment variables".', 47 | errCompilerPath: 'Failed to find the selected compiler. Make sure it\'s installed', 48 | errInitEnvVars: 'Quick build failed. Initialize the oneAPI environment. Press Ctrl+Shift+P and execute "Intel oneAPI: Initialize environment variables".', 49 | errCppSettings: 'Failed to edit C++ properties. Initialize the oneAPI environment. Press Ctrl+Shift+P and execute "Intel oneAPI: Initialize environment variables".', 50 | errCppConfiguration: 'Configure C++ properties command failed.', 51 | errNoOneApiPath: 'ONEAPI_PATH is not provided in your environment variables.', 52 | errNoOpenFile: 'Quick build failed. No open file.', 53 | errCppFile: 'Quick build failed. The open file must be a cpp file.', 54 | errReadScript: (scriptPath: string, err: Error) => `Failed to read ${scriptPath} file. ${err}`, 55 | errLog: (logPath: string) => `Quick build failed. See compile log: ${logPath}`, 56 | errExecFile: (normalizedBinaryPath: string) => `${normalizedBinaryPath} is not an executable file. Please check the app name and path and also make sure that the file has sufficient permissions to launch.`, 57 | launchAdvisor: 'Intel oneAPI: Launch Advisor', 58 | launchVTune: 'Intel oneAPI: Launch VTune Profiler', 59 | saveProjPath: 'Save the path to the project?', 60 | saveToolPath: (toolName: string) => `Save the path to the ${toolName}?`, 61 | builtFile: (dest: string) => `File ${dest} was built.`, 62 | skipTarget: 'Skip target', 63 | renameTask: 'Rename task', 64 | existedTask: (label: string) => `Task for target "${label}" already exists. Do you want to rename current task or skip target?`, 65 | newTaskName: 'Please provide new task name:', 66 | errPowerShell: 'Failed to determine version of Windows PowerShell. Unable to retrieve targets from CMake lists.', 67 | errGetTargets: (err: any) => `Failed to get targets. ${err}`, 68 | choiceExit: 'Exit', 69 | changeBinary: 'Change binary', 70 | chooseExec: 'You can choose the executable file or change the settings by yourself.', 71 | chooseExecFile: 'Choose the executable file.', 72 | choiceOnce: 'Once', 73 | choiceSave: 'Save', 74 | saveFilePath: 'Save the path to the file for analysis?', 75 | couldNotFindPath: (toolName: string, toolInstallFolder: string) => `Could not find ${toolName} by path "${toolInstallFolder}". You can ignore this problem and continue automatic search or specify the location manually.`, 76 | couldNotFind: (toolName: string) => `Could not find ${toolName}. Please specify the path manually.`, 77 | couldNotFindExec: 'Could not find executable files in workspace.', 78 | specifyPrFolder: 'Please specify the analyzer project folder', 79 | errWorkingDir: 'Can not find the working directory.', 80 | addWorkingDir: 'Please add one or more working directories and try again.', 81 | errNoWorkingDir: 'No open working directory.', 82 | failedReadScript: (scriptPath: string, err: any) => `Failed to read ${scriptPath} file. ${err}`, 83 | zzz: 'end of message list, do not use in application' 84 | }; 85 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from 'vscode-test'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to the extension test script 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests'); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import * as assert from 'assert'; 3 | import * as vscode from 'vscode'; 4 | 5 | suite('Extension Test Suite', async() => { 6 | vscode.window.showInformationMessage('Start all tests.'); 7 | await vscode.extensions.getExtension('intel-corporation.analysis-tools-launcher'); 8 | 9 | test('Sample test', () => { 10 | assert.equal([1, 2, 3].indexOf(5), -1); 11 | assert.equal([1, 2, 3].indexOf(0), -1); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd' 9 | }); 10 | 11 | const testsRoot = path.resolve(__dirname, '..'); 12 | 13 | return new Promise((resolve, reject) => { 14 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 15 | if (err) { 16 | return reject(err); 17 | } 18 | 19 | // Add files to the test suite 20 | files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f))); 21 | 22 | try { 23 | // Run the mocha test 24 | mocha.run((failures) => { 25 | if (failures > 0) { 26 | reject(new Error(`${failures} tests failed.`)); 27 | } else { 28 | resolve(); 29 | } 30 | }); 31 | } catch (err) { 32 | console.error(err); 33 | reject(err); 34 | } 35 | }); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /src/test/suite/tool.test.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import * as assert from 'assert'; 3 | import * as vscode from 'vscode'; 4 | 5 | suite('Tool Test Suite', async() => { 6 | vscode.window.showInformationMessage('Start all tests.'); 7 | 8 | test('Sample test', () => { 9 | assert.equal([1, 2, 3].indexOf(5), -1); 10 | assert.equal([1, 2, 3].indexOf(0), -1); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/test/ui/assets/Makefile: -------------------------------------------------------------------------------- 1 | DPCPP_CXX = dpcpp 2 | DPCPP_CXXFLAGS = -std=c++17 -g -o 3 | DPCPP_LDFLAGS = 4 | DPCPP_EXE_NAME = matrix_mul_dpc 5 | DPCPP_SOURCES = src/matrix_mul_dpcpp.cpp 6 | 7 | CXX = icpx 8 | OMP_CXXFLAGS = -fiopenmp -fopenmp-targets=spir64 -D__STRICT_ANSI__ -g -o 9 | OMP_LDFLAGS = 10 | OMP_EXE_NAME = matrix_mul_omp 11 | OMP_SOURCES = src/matrix_mul_omp.cpp 12 | 13 | all: 14 | $(DPCPP_CXX) $(DPCPP_CXXFLAGS) $(DPCPP_EXE_NAME) $(DPCPP_SOURCES) $(DPCPP_LDFLAGS) 15 | 16 | build_dpcpp: 17 | $(DPCPP_CXX) $(DPCPP_CXXFLAGS) $(DPCPP_EXE_NAME) $(DPCPP_SOURCES) $(DPCPP_LDFLAGS) 18 | 19 | build_omp: 20 | $(CXX) $(OMP_CXXFLAGS) $(OMP_EXE_NAME) $(OMP_SOURCES) $(OMP_LDFLAGS) 21 | 22 | 23 | run: 24 | ./$(DPCPP_EXE_NAME) 25 | 26 | run_dpcpp: 27 | ./$(DPCPP_EXE_NAME) 28 | 29 | run_omp: 30 | ./$(OMP_EXE_NAME) 31 | 32 | 33 | clean: 34 | rm -rf $(DPCPP_EXE_NAME) $(OMP_EXE_NAME) 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/test/ui/assets/hello-world.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | printf("Hello, World!"); 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/test/ui/assets/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | std::cout << "Hello world" << std::endl; 5 | } -------------------------------------------------------------------------------- /src/test/ui/assets/matrix_mul_dpcpp.cpp: -------------------------------------------------------------------------------- 1 | //============================================================== 2 | // Copyright © 2020 Intel Corporation 3 | // 4 | // SPDX-License-Identifier: MIT 5 | // ============================================================= 6 | 7 | /** 8 | * Matrix_mul multiplies two large matrices both the CPU and the offload device, 9 | * then compares results. If the code executes on both CPU and the offload 10 | * device, the name of the offload device and a success message are displayed. 11 | * 12 | * For comprehensive instructions regarding DPC++ Programming, go to 13 | * https://software.intel.com/en-us/oneapi-programming-guide and search based on 14 | * relevant terms noted in the comments. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | // dpc_common.hpp can be found in the dev-utilities include folder. 22 | // e.g., $ONEAPI_ROOT/dev-utilities//include/dpc_common.hpp 23 | #include "dpc_common.hpp" 24 | 25 | using namespace std; 26 | using namespace sycl; 27 | 28 | /** 29 | * Each element of the product matrix c[i][j] is computed from a unique row and 30 | * column of the factor matrices, a[i][k] and b[k][j] 31 | */ 32 | 33 | // Matrix size constants. 34 | constexpr int m_size = 150 * 8; // Must be a multiple of 8. 35 | constexpr int M = m_size / 8; 36 | constexpr int N = m_size / 4; 37 | constexpr int P = m_size / 2; 38 | 39 | /** 40 | * Perform matrix multiplication on host to verify results from device. 41 | */ 42 | int VerifyResult(float (*c_back)[P]); 43 | 44 | int main() { 45 | // Host memory buffer that device will write data back before destruction. 46 | float(*c_back)[P] = new float[M][P]; 47 | 48 | // Intialize c_back 49 | for (int i = 0; i < M; i++) 50 | for (int j = 0; j < P; j++) c_back[i][j] = 0.0f; 51 | 52 | // Initialize the device queue with the default selector. The device queue is 53 | // used to enqueue kernels. It encapsulates all states needed for execution. 54 | try { 55 | queue q(default_selector{}, dpc_common::exception_handler); 56 | 57 | cout << "Device: " << q.get_device().get_info() << "\n"; 58 | 59 | // Create 2D buffers for matrices, buffer c is bound with host memory c_back 60 | 61 | buffer a_buf(range(M, N)); 62 | buffer b_buf(range(N, P)); 63 | buffer c_buf(reinterpret_cast(c_back), range(M, P)); 64 | 65 | cout << "Problem size: c(" << M << "," << P << ") = a(" << M << "," << N 66 | << ") * b(" << N << "," << P << ")\n"; 67 | 68 | // Using three command groups to illustrate execution order. The use of 69 | // first two command groups for initializing matrices is not the most 70 | // efficient way. It just demonstrates the implicit multiple command group 71 | // execution ordering. 72 | 73 | // Submit command group to queue to initialize matrix a 74 | q.submit([&](auto &h) { 75 | // Get write only access to the buffer on a device. 76 | accessor a(a_buf, h, write_only); 77 | 78 | // Execute kernel. 79 | h.parallel_for(range(M, N), [=](auto index) { 80 | // Each element of matrix a is 1. 81 | a[index] = 1.0f; 82 | }); 83 | }); 84 | 85 | // Submit command group to queue to initialize matrix b 86 | q.submit([&](auto &h) { 87 | // Get write only access to the buffer on a device 88 | accessor b(b_buf, h, write_only); 89 | 90 | // Execute kernel. 91 | h.parallel_for(range(N, P), [=](auto index) { 92 | // Each column of b is the sequence 1,2,...,N 93 | b[index] = index[0] + 1.0f; 94 | }); 95 | }); 96 | 97 | // Submit command group to queue to multiply matrices: c = a * b 98 | q.submit([&](auto &h) { 99 | // Read from a and b, write to c 100 | accessor a(a_buf, h, read_only); 101 | accessor b(b_buf, h, read_only); 102 | accessor c(c_buf, h, write_only); 103 | 104 | int width_a = a_buf.get_range()[1]; 105 | 106 | // Execute kernel. 107 | h.parallel_for(range(M, P), [=](auto index) { 108 | // Get global position in Y direction. 109 | int row = index[0]; 110 | // Get global position in X direction. 111 | int col = index[1]; 112 | 113 | float sum = 0.0f; 114 | 115 | // Compute the result of one element of c 116 | for (int i = 0; i < width_a; i++) { 117 | sum += a[row][i] * b[i][col]; 118 | } 119 | 120 | c[index] = sum; 121 | }); 122 | }); 123 | } catch (sycl::exception const &e) { 124 | cout << "An exception is caught while multiplying matrices.\n"; 125 | terminate(); 126 | } 127 | 128 | int result; 129 | cout << "Result of matrix multiplication using DPC++: "; 130 | result = VerifyResult(c_back); 131 | delete[] c_back; 132 | 133 | return result; 134 | } 135 | 136 | bool ValueSame(float a, float b) { 137 | return fabs(a - b) < numeric_limits::epsilon(); 138 | } 139 | 140 | int VerifyResult(float (*c_back)[P]) { 141 | // Check that the results are correct by comparing with host computing. 142 | int i, j, k; 143 | 144 | // 2D arrays on host side. 145 | float(*a_host)[N] = new float[M][N]; 146 | float(*b_host)[P] = new float[N][P]; 147 | float(*c_host)[P] = new float[M][P]; 148 | 149 | // Each element of matrix a is 1. 150 | for (i = 0; i < M; i++) 151 | for (j = 0; j < N; j++) a_host[i][j] = 1.0f; 152 | 153 | // Each column of b_host is the sequence 1,2,...,N 154 | for (i = 0; i < N; i++) 155 | for (j = 0; j < P; j++) b_host[i][j] = i + 1.0f; 156 | 157 | // c_host is initialized to zero. 158 | for (i = 0; i < M; i++) 159 | for (j = 0; j < P; j++) c_host[i][j] = 0.0f; 160 | 161 | for (i = 0; i < M; i++) { 162 | for (k = 0; k < N; k++) { 163 | // Each element of the product is just the sum 1+2+...+n 164 | for (j = 0; j < P; j++) { 165 | c_host[i][j] += a_host[i][k] * b_host[k][j]; 166 | } 167 | } 168 | } 169 | 170 | bool mismatch_found = false; 171 | 172 | // Compare host side results with the result buffer from device side: print 173 | // mismatched data 5 times only. 174 | int print_count = 0; 175 | 176 | for (i = 0; i < M; i++) { 177 | for (j = 0; j < P; j++) { 178 | if (!ValueSame(c_back[i][j], c_host[i][j])) { 179 | cout << "Fail - The result is incorrect for element: [" << i << ", " 180 | << j << "], expected: " << c_host[i][j] 181 | << ", but found: " << c_back[i][j] << "\n"; 182 | mismatch_found = true; 183 | print_count++; 184 | if (print_count == 5) break; 185 | } 186 | } 187 | 188 | if (print_count == 5) break; 189 | } 190 | 191 | delete[] a_host; 192 | delete[] b_host; 193 | delete[] c_host; 194 | 195 | if (!mismatch_found) { 196 | cout << "Success - The results are correct!\n"; 197 | return 0; 198 | } else { 199 | cout << "Fail - The results mismatch!\n"; 200 | return -1; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/test/ui/configs/.mocharc-debug.js: -------------------------------------------------------------------------------- 1 | module.exports ={ 2 | timeout: 9999999 3 | } -------------------------------------------------------------------------------- /src/test/ui/configs/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.simpleDialog.enable": true, 3 | "window.dialogStyle": "custom" 4 | } -------------------------------------------------------------------------------- /src/test/ui/launcherTest.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-expressions */ 2 | /* eslint-disable no-undef */ 3 | /* eslint-disable no-unused-vars */ 4 | import { Workbench, VSBrowser, WebDriver, Notification, NotificationType } from 'vscode-extension-tester'; 5 | import { execSync } from 'child_process'; 6 | import { expect } from 'chai'; 7 | import { mkdirSync } from 'fs'; 8 | import * as path from 'path'; 9 | 10 | describe('Launcher Extension basic tests', () => { 11 | let browser: VSBrowser; 12 | let workbench: Workbench; 13 | // let driver: WebDriver; 14 | let executablePath: string; 15 | const workspacePath = path.join(process.cwd(), 'test-data', 'launchers-workspace'); 16 | 17 | let text: string; 18 | 19 | before(() => { 20 | mkdirSync(workspacePath, { recursive: true }); 21 | const sourcePath = path.join(process.cwd(), 'src', 'test', 'ui', 'assets', 'hello-world.c'); 22 | 23 | executablePath = path.join(workspacePath, 'hello-world'); 24 | execSync(`gcc ${sourcePath} -o ${executablePath}`); 25 | }); 26 | 27 | before(async function() { 28 | browser = VSBrowser.instance; 29 | await browser.waitForWorkbench(); 30 | // driver = browser.driver; 31 | workbench = new Workbench(); 32 | }); 33 | 34 | describe('Check recommended extensions', async function() { 35 | it('Get installed Extension list', async function() { 36 | const extensionView = await workbench.getActivityBar().getViewControl('Extensions'); 37 | 38 | await extensionView?.openView(); 39 | const sidebar = workbench.getSideBar(); 40 | const sidebarView = sidebar.getContent(); 41 | const instExt = await sidebarView.getSection('Installed'); 42 | 43 | text = await instExt.getText(); 44 | }); 45 | 46 | it('Contain the correct number of notifications', async function() { 47 | const center = await workbench.openNotificationsCenter(); 48 | const notifications = await center.getNotifications(NotificationType.Any); 49 | 50 | if (text.includes('Environment Configurator')) { 51 | expect(notifications.length).equal(0); 52 | } else { 53 | expect(notifications.length).equal(1); 54 | } 55 | }); 56 | 57 | it('Install Env configurator', async function() { 58 | const center = await workbench.openNotificationsCenter(); 59 | const notifications = await center.getNotifications(NotificationType.Any); 60 | const actions = await notifications[0]?.getActions(); 61 | 62 | if (actions) { 63 | const title = await actions[0]?.getTitle(); 64 | 65 | await notifications[0].takeAction(title); 66 | } 67 | }); 68 | 69 | it('Environment Configurator was installed', async function() { 70 | expect(text).include('Environment Configurator for Intel® oneAPI Toolkits'); 71 | }); 72 | }); 73 | 74 | // it('VTune should run', async function() { 75 | // this.timeout(30000); 76 | 77 | // await workbench.executeCommand('vtune'); 78 | // // const dialog = await DialogHandler.getOpenDialog(); 79 | // // await dialog.selectPath(executablePath); 80 | // // await dialog.confirm(); // Confirm executable path (once for all tests) 81 | // // await dialog.confirm(); // Confirm install path 82 | // // await dialog.confirm(); // Confirm project path 83 | 84 | // await browser.driver.sleep(1500); 85 | // expect(execSync('ps -a | grep vtune-gui').includes('vtune-gui')).to.be.true; 86 | // execSync('killall -9 vtune-gui'); 87 | // }); 88 | 89 | // it('Advisor should run', async function() { 90 | // this.timeout(30000); 91 | 92 | // await browser.driver.sleep(3000); 93 | // await workbench.executeCommand('advisor'); 94 | // // const dialog = await DialogHandler.getOpenDialog(); 95 | 96 | // // await dialog.confirm(); // Confirm install path 97 | // // await dialog.confirm(); // Confirm project path 98 | 99 | // await browser.driver.sleep(1500); 100 | // expect(execSync('ps -a | grep advisor-gui').includes('advisor-gui')).to.be.true; 101 | // execSync('killall -9 advisor-gui'); 102 | // }); 103 | 104 | // after(() => { 105 | // rmdirSync(workspacePath, { recursive: true }); 106 | // }); 107 | // }); 108 | 109 | // describe('Generating tasks and launch configuration', async function() { 110 | // const samplePath = path.join(process.cwd(), 'test-data', 'sample'); 111 | // const vscodeConfigsPath = path.join(samplePath, '.vscode'); 112 | // const makefilePath = path.join(process.cwd(), 'src', 'test', 'ui', 'assets', 'Makefile'); 113 | // let driver: WebDriver; 114 | 115 | // before(async function() { 116 | // this.timeout(20000); 117 | // mkdirSync(samplePath, { recursive: true }); 118 | // copyFileSync(makefilePath, path.join(samplePath, 'Makefile')); 119 | // driver = VSBrowser.instance.driver; 120 | // }); 121 | 122 | // describe('Intel oneAPI: Generate tasks', async function() { 123 | // before(async function() { 124 | // this.timeout(20000); 125 | // const workbench = new Workbench(); 126 | // await workbench.executeCommand('File: Open Folder'); 127 | // // const dialog = await DialogHandler.getOpenDialog(); 128 | // // await dialog.selectPath(samplePath); 129 | // // await dialog.confirm(); 130 | // }); 131 | 132 | // it('Quick pick contain command', async function() { 133 | // this.timeout(10000); 134 | // const workbench = new Workbench(); 135 | // const input = await workbench.openCommandPrompt() as InputBox; 136 | // await input.setText('>Intel oneAPI: Generate tasks'); 137 | // const pick = await input.findQuickPick('Intel oneAPI: Generate tasks'); 138 | // expect(pick).not.undefined; 139 | // }); 140 | 141 | // it('Quick pick contain \'build_dpcpp\' task after executing \'Generate tasks\' command', async function() { 142 | // this.timeout(10000); 143 | // const workbench = new Workbench(); 144 | // const input = await workbench.openCommandPrompt() as InputBox; 145 | // await input.setText('>Intel oneAPI: Generate tasks'); 146 | // await input.selectQuickPick('Intel oneAPI: Generate tasks'); 147 | // await driver.sleep(1000); 148 | 149 | // const pick = await input.findQuickPick('build_dpcpp'); 150 | // await driver.sleep(1000); 151 | // expect(pick).not.undefined; 152 | // }); 153 | 154 | // it('Adding the task shows a notification with the correct text', async function() { 155 | // this.timeout(10000); 156 | // const workbench = new Workbench(); 157 | // const input = await workbench.openCommandPrompt() as InputBox; 158 | // await input.setText('>Intel oneAPI: Generate tasks'); 159 | // await input.selectQuickPick('Intel oneAPI: Generate tasks'); 160 | // await driver.sleep(1000); 161 | // await input.selectQuickPick('build_dpcpp'); 162 | // await driver.sleep(1000); 163 | // const notification = await driver.wait(async() => { 164 | // return await getNotifications('Task for "build_dpcpp" was added'); 165 | // }, 10000) as Notification; 166 | // expect(await notification.getType()).equals(NotificationType.Info); 167 | // }); 168 | 169 | // it('.vscode folder contains tasks.json file', function() { 170 | // const task = path.join(vscodeConfigsPath, 'tasks.json'); 171 | // expect(existsSync(task)).equals(true); 172 | // }); 173 | // }); 174 | 175 | // describe('Intel oneAPI: Generate launch configurations', function() { 176 | // it('Quick pick contain command', async function() { 177 | // this.timeout(10000); 178 | // const workbench = new Workbench(); 179 | // const input = await workbench.openCommandPrompt() as InputBox; 180 | // await input.setText('>Intel oneAPI: Generate launch configurations'); 181 | // const pick = await input.findQuickPick('Intel oneAPI: Generate launch configurations'); 182 | // expect(pick).not.undefined; 183 | // }); 184 | 185 | // it('Quick pick contain fake executable', async function() { 186 | // this.timeout(10000); 187 | // const workbench = new Workbench(); 188 | // await workbench.executeCommand('Intel oneAPI: Generate launch configurations'); 189 | // await driver.sleep(1000); 190 | // const input = new InputBox(); 191 | // const pick = await input.findQuickPick('Put temporal target path "a.out" to replace it later with correct path manually'); 192 | // await input.cancel(); 193 | 194 | // // close warning about debugging 195 | // const dialog = new ModalDialog(); 196 | // await dialog.pushButton('OK'); 197 | 198 | // expect(pick).not.undefined; 199 | // }); 200 | 201 | // it('Command shows a notification with the correct text', async function() { 202 | // this.timeout(10000); 203 | // const workbench = new Workbench(); 204 | // workbench.executeCommand('Intel oneAPI: Generate launch configurations'); 205 | // await driver.sleep(1000); 206 | // const input = new InputBox(); 207 | // await input.selectQuickPick('Put temporal target path "a.out" to replace it later with correct path manually'); 208 | 209 | // // close note about debugging launch template 210 | // const dialog = new ModalDialog(); 211 | // await dialog.pushButton('OK'); 212 | 213 | // await input.cancel(); 214 | // await input.cancel(); 215 | // await input.cancel(); 216 | 217 | // // close debug warning on non-CPU devices 218 | // const debugWarning = new ModalDialog(); 219 | // await debugWarning.pushButton('OK'); 220 | 221 | // const notification = await driver.wait(async() => { 222 | // return await getNotifications('Launch configuration "Launch_template" for "a.out" was added'); 223 | // }, 10000) as Notification; 224 | // expect(await notification.getType()).equals(NotificationType.Info); 225 | // }); 226 | 227 | // it('.vscode folder contains launch.json file', function() { 228 | // this.timeout(10000); 229 | // const launch = path.join(vscodeConfigsPath, 'launch.json'); 230 | // expect(existsSync(launch)).equals(true); 231 | // }); 232 | // }); 233 | // after(() => { 234 | // rmdirSync(samplePath, { recursive: true }); 235 | // }); 236 | // }); 237 | 238 | // describe('Quick build functions', async function() { 239 | // // eslint-disable-next-line no-unused-vars 240 | // let driver: WebDriver; 241 | // before(async function() { 242 | // driver = VSBrowser.instance.driver; 243 | // }); 244 | // describe('Intel oneAPI: Quick build current file with ICPX', async function() { 245 | // const sourcePath = path.join(process.cwd(), 'src', 'test', 'ui', 'assets', 'hello-world.cpp'); 246 | 247 | // before(async function() { 248 | // this.timeout(20000); 249 | // const workbench = new Workbench(); 250 | // const input = await workbench.openCommandPrompt() as InputBox; 251 | // await input.setText('>File: Open File'); 252 | // await input.selectQuickPick('File: Open File'); 253 | // // const dialog = await DialogHandler.getOpenDialog(); 254 | // // await dialog.selectPath(sourcePath); 255 | // // await dialog.confirm(); 256 | // }); 257 | 258 | // it('Quick pick contain command', async function() { 259 | // this.timeout(10000); 260 | // const workbench = new Workbench(); 261 | // const input = await workbench.openCommandPrompt() as InputBox; 262 | // await input.setText('>Intel oneAPI: Quick build current file with ICPX'); 263 | // const pick = await input.findQuickPick('Intel oneAPI: Quick build current file with ICPX'); 264 | // expect(pick).not.undefined; 265 | // }); 266 | 267 | // // TODO:Oneapi environment required 268 | 269 | // // it('A binary file is built', async function () { 270 | // // this.timeout(10000); 271 | // // const workbench = new Workbench(); 272 | // // const input = await workbench.openCommandPrompt() as InputBox; 273 | // // await input.setText('>Intel oneAPI: Quick build current file with ICPX'); 274 | // // await input.selectQuickPick('Intel oneAPI: Quick build current file with ICPX'); 275 | 276 | // // await driver.sleep(5000); 277 | // // expect(existsSync(binaryPath)).equals(true); 278 | // // }); 279 | 280 | // // after(async function () { 281 | // // unlinkSync(binaryPath); 282 | // // }); 283 | // }); 284 | 285 | // describe('Intel oneAPI: Quick build current file with ICPX and SYCL enabled', async function() { 286 | // const sourcePath = path.join(process.cwd(), 'src', 'test', 'ui', 'assets', 'matrix_mul_dpcpp.cpp'); 287 | 288 | // before(async function() { 289 | // this.timeout(20000); 290 | // const workbench = new Workbench(); 291 | // const input = await workbench.openCommandPrompt() as InputBox; 292 | // await input.setText('>File: Open File'); 293 | // await input.selectQuickPick('File: Open File'); 294 | // // const dialog = await DialogHandler.getOpenDialog(); 295 | // // await dialog.selectPath(sourcePath); 296 | // // await dialog.confirm(); 297 | // }); 298 | 299 | // it('Quick pick contain command', async function() { 300 | // this.timeout(10000); 301 | // const workbench = new Workbench(); 302 | // const input = await workbench.openCommandPrompt() as InputBox; 303 | // await input.setText('>Intel oneAPI: Quick build current file with ICPX and SYCL enabled'); 304 | // const pick = await input.findQuickPick('Intel oneAPI: Quick build current file with ICPX and SYCL enabled'); 305 | // expect(pick).not.undefined; 306 | // }); 307 | 308 | // // TODO:Oneapi environment required 309 | 310 | // // it('A binary file is built', async function () { 311 | // // this.timeout(10000); 312 | // // const workbench = new Workbench(); 313 | // // const input = await workbench.openCommandPrompt() as InputBox; 314 | // // await input.setText('>Intel oneAPI: Quick build current file with ICPX'); 315 | // // await input.selectQuickPick('Intel oneAPI: Quick build current file with ICPX'); 316 | // // expect(existsSync(binaryPath)).equals(true); 317 | // // }); 318 | 319 | // // after(async function () { 320 | // // unlinkSync(binaryPath); 321 | // // }); 322 | // }); 323 | }); 324 | 325 | // async function getNotifications(text: string): Promise { 326 | // const notifications = await new Workbench().getNotifications(); 327 | // for (const notification of notifications) { 328 | // const message = await notification.getMessage(); 329 | // if (message.indexOf(text) >= 0) { 330 | // return notification; 331 | // } 332 | // } 333 | // } 334 | -------------------------------------------------------------------------------- /src/utils/CPUAttributes.ts: -------------------------------------------------------------------------------- 1 | export const cpuAttributesTooltips = { 2 | alloc_section: { 3 | description: 'Allocates one or more variables in the specified section. Controls section attribute specification for variables.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/alloc-section.html)', 4 | signature: '#pragma alloc_section(var1,var2,..., "r;attribute-list")' 5 | }, 6 | block_loop: { 7 | description: 'Enables loop blocking for the immediately following nested loops. block_loop enables loop blocking for the nested loops. noblock_loop disables loop blocking for the nested loops.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/block-loop-noblock-loop.html)', 8 | signature: '#pragma block_loop [clause[,clause]...]' 9 | }, 10 | noblock_loop: { 11 | description: 'Disables loop blocking for the immediately following nested loops. block_loop enables loop blocking for the nested loops. noblock_loop disables loop blocking for the nested loops.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/block-loop-noblock-loop.html)', 12 | signature: '#pragma noblock_loop' 13 | }, 14 | code_align: { 15 | description: 'Specifies the byte alignment for a loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/code-align.html)', 16 | signature: '#pragma code_align(n)' 17 | }, 18 | distribute_point: { 19 | description: 'Instructs the compiler to prefer loop distribution at the location indicated.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/distribute-point.html)', 20 | signature: '#pragma distribute_point' 21 | }, 22 | inline: { 23 | description: 'The inline pragma is a hint to the compiler that the user prefers that the calls in question be inlined, but expects the compiler not to inline them if its heuristics determine that the inlining would be overly aggressive and might slow down the compilation of the source code excessively, create too large of an executable, or degrade performance.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/inline-noinline-forceinline.html)', 24 | signature: '#pragma inline [recursive]' 25 | }, 26 | forceinline: { 27 | description: 'The forceinline pragma indicates that the calls in question should be inlined whenever the compiler is capable of doing so.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/inline-noinline-forceinline.html)', 28 | signature: '#pragma forceinline [recursive]' 29 | }, 30 | noinline: { 31 | description: 'The noinline pragma indicates that the calls in question should not be inlined.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/inline-noinline-forceinline.html)', 32 | signature: '#pragma noinline' 33 | }, 34 | intel_omp_task: { 35 | description: 'For Intel legacy tasking, specifies a unit of work, potentially executed by a different thread.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/intel-omp-task.html)', 36 | signature: '#pragma intel_omp_task [clause[[,]clause]...]' 37 | }, 38 | intel_omp_taskq: { 39 | description: 'For Intel legacy tasking, specifies an environment for the while loop in which to queue the units of work specified by the enclosed task pragma.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/intel-omp-taskq.html)', 40 | signature: '#pragma intel_omp_taskq[clause[[,]clause]...]' 41 | }, 42 | loop_count: { 43 | description: 'Specifies the iterations for a for loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/loop-count.html)', 44 | signature: '#pragma loop_count' 45 | }, 46 | nofusion: { 47 | description: 'Prevents a loop from fusing with adjacent loops.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/nofusion.html)', 48 | signature: '#pragma nofusion' 49 | }, 50 | novector: { 51 | description: 'Specifies that a particular loop should never be vectorized.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/novector.html)', 52 | signature: '#pragma novector' 53 | }, 54 | 'omp simd early_exit': { 55 | description: 'Extends #pragma omp SIMD, allowing vectorization of multiple exit loops.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/omp-simd-early-exit.html)', 56 | signature: '#pragma omp simd early_exit' 57 | }, 58 | optimize: { 59 | description: 'Enables or disables optimizations for code after this pragma until another optimize pragma or end of the translation unit.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/optimize.html)', 60 | signature: '#pragma optimize("", on|off)' 61 | }, 62 | optimization_level: { 63 | description: 'Controls optimization for one function or all functions after its first occurrence.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/optimization-level.html)', 64 | signature: '#pragma [intel|GCC] optimization_level n' 65 | }, 66 | optimization_parameter: { 67 | description: 'Passes certain information about a function to the optimizer.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/optimization-parameter.html)', 68 | signature: '#pragma intel optimization_parameter' 69 | }, 70 | parallel: { 71 | description: 'Resolves dependencies to facilitate auto-parallelization of the immediately following loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/parallel-noparallel.html)', 72 | signature: '#pragma parallel [clause[ [,]clause]...]' 73 | }, 74 | noparallel: { 75 | description: 'Prevents auto-parallelization of the immediately following loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/parallel-noparallel.html)', 76 | signature: '#pragma noparallel' 77 | }, 78 | prefetch: { 79 | description: 'This pragma hints to the compiler to generate data prefetches for some memory references. These hints affect the heuristics used in the compiler. Prefetching data can minimize the effects of memory latency.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/prefetch-noprefetch.html)', 80 | signature: '#pragma prefetch' 81 | }, 82 | noprefetch: { 83 | description: 'The noprefetch pragma hints to the compiler not to generate data prefetches for some memory references. This affects the heuristics used in the compiler.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/prefetch-noprefetch.html)', 84 | signature: '#pragma noprefetch [var1 [, var2]...]' 85 | }, 86 | simd: { 87 | description: 'The SIMD pragma is used to guide the compiler to vectorize more loops. Vectorization using the SIMD pragma complements (but does not replace) the fully automatic approach.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/simd.html)', 88 | signature: '#pragma simd [clause[ [,] clause]...]' 89 | }, 90 | simdoff: { 91 | description: 'Specifies a block of code in the SIMD loop or SIMD-enabled function that should be executed serially, in a logical order of SIMD lanes.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/simdoff.html)', 92 | signature: '#pragma simdoff' 93 | }, 94 | unroll: { 95 | description: 'The unroll[n] pragma tells the compiler how many times to unroll a counted loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/unroll-nounroll.html)', 96 | signature: '#pragma unroll(n)' 97 | }, 98 | nounroll: { 99 | description: 'The nounroll pragma instructs the compiler not to unroll a specified loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/unroll-nounroll.html)', 100 | signature: '#pragma nounroll' 101 | }, 102 | unroll_and_jam: { 103 | description: 'The unroll_and_jam pragma partially unrolls one or more loops higher in the nest than the innermost loop and fuses/jams the resulting loops back together. This transformation allows more reuses in the loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/unroll-and-jam-nounroll-and-jam.html)', 104 | signature: '#pragma unroll_and_jam (n)' 105 | }, 106 | nounroll_and_jam: { 107 | description: 'When unrolling a loop increases register pressure and code size, it may be necessary to prevent unrolling of a nested loop or an imperfect nested loop. In such cases, use the nounroll_and_jam pragma. The nounroll_and_jam pragma hints to the compiler not to unroll a specified loop.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/unroll-and-jam-nounroll-and-jam.html)', 108 | signature: '#pragma nounroll_and_jam' 109 | }, 110 | vector: { 111 | description: 'Tells the compiler that the loop should be vectorized according to the argument keywords.\n\n[Learn more](https://www.intel.com/content/www/us/en/develop/documentation/oneapi-dpcpp-cpp-compiler-dev-guide-and-reference/top/compiler-reference/pragmas/intel-specific-pragma-reference/vector.html)', 112 | signature: '#pragma vector {always[assert]|aligned|unaligned|dynamic_align[(var)]|nodynamic_align|temporal|nontemporal|[no]vecremainder|[no]mask_readwrite|vectorlength(n1[, n2]...)}' 113 | } 114 | }; 115 | 116 | export const cpuAttributesSnippets = { 117 | 'alloc_section(var1,var2,..., \'r;attribute-list\')': { 118 | description: 'Allocates one or more variables in the specified section. Controls section attribute specification for variables.', 119 | prefix: '#pragma alloc_section', 120 | body: [ 121 | '#pragma alloc_section' 122 | ] 123 | }, 124 | 'block_loop [clause[,clause]...]': { 125 | description: 'Enables loop blocking for the immediately following nested loops. block_loop enables loop blocking for the nested loops. noblock_loop disables loop blocking for the nested loops.', 126 | prefix: '#pragma block_loop', 127 | body: [ 128 | '#pragma block_loop' 129 | ] 130 | }, 131 | noblock_loop: { 132 | description: 'Disables loop blocking for the immediately following nested loops. block_loop enables loop blocking for the nested loops. noblock_loop disables loop blocking for the nested loops.', 133 | prefix: '#pragma noblock_loop', 134 | body: [ 135 | '#pragma noblock_loop' 136 | ] 137 | }, 138 | 'code_align(n)': { 139 | description: 'Specifies the byte alignment for a loop', 140 | prefix: '#pragma code_align', 141 | body: [ 142 | '#pragma code_align' 143 | ] 144 | }, 145 | distribute_point: { 146 | description: 'Instructs the compiler to prefer loop distribution at the location indicated.', 147 | prefix: '#pragma distribute_point', 148 | body: [ 149 | '#pragma distribute_point' 150 | ] 151 | }, 152 | 'inline [recursive]': { 153 | description: 'The inline pragma is a hint to the compiler that the user prefers that the calls in question be inlined, but expects the compiler not to inline them if its heuristics determine that the inlining would be overly aggressive and might slow down the compilation of the source code excessively, create too large of an executable, or degrade performance.', 154 | prefix: '#pragma inline', 155 | body: [ 156 | '#pragma inline' 157 | ] 158 | }, 159 | 'forceinline [recursive]': { 160 | description: 'The forceinline pragma indicates that the calls in question should be inlined whenever the compiler is capable of doing so.', 161 | prefix: '#pragma forceinline', 162 | body: [ 163 | '#pragma forceinline' 164 | ] 165 | }, 166 | noinline: { 167 | description: 'The noinline pragma indicates that the calls in question should not be inlined.', 168 | prefix: '#pragma noinline', 169 | body: [ 170 | '#pragma noinline' 171 | ] 172 | }, 173 | 'intel_omp_task [clause[[,]clause]...]': { 174 | description: 'For Intel legacy tasking, specifies a unit of work, potentially executed by a different thread.', 175 | prefix: '#pragma intel_omp_task', 176 | body: [ 177 | '#pragma intel_omp_task' 178 | ] 179 | }, 180 | 'intel_omp_taskq[clause[[,]clause]...]': { 181 | description: 'For Intel legacy tasking, specifies an environment for the while loop in which to queue the units of work specified by the enclosed task pragma.', 182 | prefix: '#pragma intel_omp_taskq', 183 | body: [ 184 | '#pragma intel_omp_taskq' 185 | ] 186 | }, 187 | loop_count: { 188 | description: 'Specifies the iterations for a for loop.', 189 | prefix: '#pragma loop_count', 190 | body: [ 191 | '#pragma loop_count' 192 | ] 193 | }, 194 | nofusion: { 195 | description: 'Prevents a loop from fusing with adjacent loops.', 196 | prefix: '#pragma nofusion', 197 | body: [ 198 | '#pragma nofusion' 199 | ] 200 | }, 201 | novector: { 202 | description: 'Specifies that a particular loop should never be vectorized.', 203 | prefix: '#pragma novector', 204 | body: [ 205 | '#pragma novector' 206 | ] 207 | }, 208 | 'omp simd early_exit': { 209 | description: 'Extends #pragma omp simd, allowing vectorization of multiple exit loops.', 210 | prefix: '#pragma omp simd early_exit', 211 | body: [ 212 | '#pragma omp simd early_exit' 213 | ] 214 | }, 215 | 'optimize(\'\', on|off)': { 216 | description: 'Enables or disables optimizations for code after this pragma until another optimize pragma or end of the translation unit.', 217 | prefix: '#pragma optimize', 218 | body: [ 219 | '#pragma optimize' 220 | ] 221 | }, 222 | 'optimization_level n': { 223 | description: 'Controls optimization for one function or all functions after its first occurrence.', 224 | prefix: '#pragma optimization_level', 225 | body: [ 226 | '#pragma optimization_level' 227 | ] 228 | }, 229 | optimization_parameter: { 230 | description: 'Passes certain information about a function to the optimizer.', 231 | prefix: '#pragma intel optimization_parameter', 232 | body: [ 233 | '#pragma intel optimization_parameter' 234 | ] 235 | }, 236 | 'parallel [clause[ [,]clause]...]': { 237 | description: 'Resolves dependencies to facilitate auto-parallelization of the immediately following loop.', 238 | prefix: '#pragma parallel', 239 | body: [ 240 | '#pragma parallel' 241 | ] 242 | }, 243 | noparallel: { 244 | description: 'Prevents auto-parallelization of the immediately following loop.', 245 | prefix: '#pragma noparallel', 246 | body: [ 247 | '#pragma noparallel' 248 | ] 249 | }, 250 | prefetch: { 251 | description: 'This pragma hints to the compiler to generate data prefetches for some memory references. These hints affect the heuristics used in the compiler. Prefetching data can minimize the effects of memory latency.', 252 | prefix: '#pragma prefetch', 253 | body: [ 254 | '#pragma prefetch' 255 | ] 256 | }, 257 | 'noprefetch [var1 [, var2]...]': { 258 | description: 'The noprefetch pragma hints to the compiler not to generate data prefetches for some memory references. This affects the heuristics used in the compiler.', 259 | prefix: '#pragma noprefetch', 260 | body: [ 261 | '#pragma noprefetch' 262 | ] 263 | }, 264 | 'simd [clause[ [,] clause]...]': { 265 | description: 'The SIMD pragma is used to guide the compiler to vectorize more loops. Vectorization using the simd pragma complements (but does not replace) the fully automatic approach.', 266 | prefix: '#pragma simd', 267 | body: [ 268 | '#pragma simd' 269 | ] 270 | }, 271 | simdoff: { 272 | description: 'Specifies a block of code in the SIMD loop or SIMD-enabled function that should be executed serially, in a logical order of SIMD lanes.', 273 | prefix: '#pragma simdoff', 274 | body: [ 275 | '#pragma simdoff' 276 | ] 277 | }, 278 | 'unroll(n)': { 279 | description: 'The unroll[n] pragma tells the compiler how many times to unroll a counted loop.', 280 | prefix: '#pragma unroll', 281 | body: [ 282 | '#pragma unroll' 283 | ] 284 | }, 285 | nounroll: { 286 | description: 'The nounroll pragma instructs the compiler not to unroll a specified loop.', 287 | prefix: '#pragma nounroll', 288 | body: [ 289 | '#pragma nounroll' 290 | ] 291 | }, 292 | 'unroll_and_jam (n)': { 293 | description: 'The unroll_and_jam pragma partially unrolls one or more loops higher in the nest than the innermost loop and fuses/jams the resulting loops back together. This transformation allows more reuses in the loop.', 294 | prefix: '#pragma unroll_and_jam (n)', 295 | body: [ 296 | '#pragma unroll_and_jam (n)' 297 | ] 298 | }, 299 | nounroll_and_jam: { 300 | description: 'When unrolling a loop increases register pressure and code size it may be necessary to prevent unrolling of a nested loop or an imperfect nested loop. In such cases, use the nounroll_and_jam pragma. The nounroll_and_jam pragma hints to the compiler not to unroll a specified loop.', 301 | prefix: '#pragma nounroll_and_jam', 302 | body: [ 303 | '#pragma nounroll_and_jam' 304 | ] 305 | }, 306 | vector: { 307 | description: 'Tells the compiler that the loop should be vectorized according to the argument keywords.', 308 | prefix: '#pragma vector', 309 | body: [ 310 | '#pragma vector' 311 | ] 312 | } 313 | }; 314 | -------------------------------------------------------------------------------- /src/utils/snippets.ts: -------------------------------------------------------------------------------- 1 | import { cpuAttributesSnippets } from './CPUAttributes'; 2 | 3 | (async function() { 4 | const fs = require('fs').promises; 5 | const path = require('path'); 6 | const xml2js = require('xml2js'); 7 | 8 | const parser = new xml2js.Parser(); 9 | const fpgaMemoryAttributes: any = { 10 | ' ': { 11 | prefix: 'intel', 12 | body: [ 13 | 'intel::' 14 | ], 15 | description: ' ' 16 | } 17 | }; 18 | const files = [path.join(__dirname, '/../../attributes/kernel.xml'), path.join(__dirname, '/../../attributes/loop.xml'), path.join(__dirname, '/../../attributes/memory.xml')]; 19 | 20 | await Promise.all(files.map(async(file) => { 21 | const data = await fs.readFile(file, 'utf8'); 22 | 23 | parser.parseStringPromise(data).then((result: any) => { 24 | const attributes = result.reference ? result.reference.refbody[0].table[0].tgroup[0].tbody[0].row : result.concept.conbody[0].table[0].tgroup[0].tbody[0].row; 25 | 26 | for (const att of attributes) { 27 | const name = att.entry[0].codeph[0].replace(/[[\]']+/g, '').replace('intel::', '').replace(/\r\n/g, '').trim(); 28 | const description = (att.entry[1]._ || att.entry[1].p[0]._ || att.entry[1].p[0])?.replace(/\s+/g, ' ').trim(); 29 | const prefix = att.entry[0].codeph[0].replace(/\(.*\)/, '').replace(/[[\]']+/g, '').replace(/\r\n/g, '').trim(); 30 | 31 | fpgaMemoryAttributes[name] = { 32 | description, 33 | prefix, 34 | body: [prefix] 35 | }; 36 | } 37 | }); 38 | })); 39 | await fs.writeFile('snippets.json', JSON.stringify({ ...fpgaMemoryAttributes, ...cpuAttributesSnippets }, null, 4), function(err: Error) { 40 | if (err) throw err; 41 | console.log('File was successfully rewritten.'); 42 | }); 43 | }()); 44 | -------------------------------------------------------------------------------- /src/utils/utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Intel Corporation 3 | * Licensed under the MIT License. See the project root LICENSE 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | 'use strict'; 9 | import * as vscode from 'vscode'; 10 | import { execSync } from 'child_process'; 11 | import * as fs from 'fs'; 12 | import * as fsPromises from 'fs/promises'; 13 | import * as path from 'path'; 14 | import messages from '../messages'; 15 | 16 | export function getPSexecutableName(): string | undefined { 17 | let execName: string; 18 | 19 | try { 20 | execSync('pwsh'); 21 | execName = 'pwsh'; 22 | } catch (err) { 23 | try { 24 | execSync('powershell'); 25 | execName = 'powershell'; 26 | } catch (err) { 27 | return undefined; 28 | } 29 | } 30 | return execName; 31 | } 32 | 33 | // Return the uri corresponding to the base folder of the item currently selected in the explorer. 34 | // If the node is not given, ask the user to select the base folder. 35 | export function getBaseUri(node: vscode.Uri): vscode.Uri | undefined { 36 | let baseUri: vscode.Uri | undefined; 37 | 38 | // If only one folder, just return its uri 39 | const folders = vscode.workspace.workspaceFolders; 40 | 41 | if (folders && folders.length === 1) { 42 | baseUri = folders[0].uri; 43 | } 44 | 45 | // Get the folder corresponding to the selected node 46 | if (node) { 47 | const folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(node); 48 | 49 | if (folder) { 50 | baseUri = folder.uri; 51 | } 52 | } 53 | 54 | return baseUri; 55 | } 56 | 57 | export async function checkIfPathExist(normalizedPath: string): Promise { 58 | if (!normalizedPath) return false; 59 | try { 60 | await fsPromises.access(normalizedPath, fs.constants.R_OK); 61 | return true; 62 | } catch (err: any) { 63 | if (err.code === 'ENOENT') { 64 | // file does not exist 65 | return false; 66 | } else { 67 | vscode.window.showErrorMessage(`Failed to check that ${path.basename(normalizedPath)} exists. ${err}`); 68 | return false; 69 | } 70 | } 71 | } 72 | 73 | export async function removeScriptPath(normalizedPath: string) { 74 | if (!normalizedPath) return; 75 | if (await checkIfPathExist(normalizedPath)) { 76 | fs.unlink(normalizedPath, (err) => { 77 | if (err) { 78 | vscode.window.showErrorMessage(`Failed to delete file ${normalizedPath}. ${err}`); 79 | } 80 | }); 81 | } 82 | } 83 | 84 | function readBytes(fd: number, sharedBuffer: Buffer) { 85 | return new Promise((resolve, reject) => { 86 | fs.read( 87 | fd, 88 | sharedBuffer, 89 | 0, 90 | sharedBuffer.length, 91 | null, 92 | (err, bytesRead: number, buffer: any) => { 93 | if (err) { return reject(err.message); } 94 | resolve(buffer); 95 | } 96 | ); 97 | }); 98 | } 99 | 100 | async function checkValidMagicNumber(filePath: string): Promise { 101 | const sharedBuffer = Buffer.alloc(4); 102 | const fd = fs.openSync(filePath, 'r'); 103 | 104 | try { 105 | const buffer = await readBytes(fd, sharedBuffer); 106 | const firstBytes = buffer.toString('utf8', 0, 4); 107 | 108 | if (process.platform === 'win32' && firstBytes.indexOf('MZ') !== -1) { 109 | return true; 110 | } else if (firstBytes.indexOf('ELF') !== -1) { 111 | return true; 112 | } 113 | return false; 114 | } catch { 115 | return false; 116 | } 117 | } 118 | 119 | export async function checkExecFile(normalizedPath: string): Promise { 120 | const isExist = await checkIfPathExist(normalizedPath); 121 | 122 | if (normalizedPath === '' || !isExist || !fs.statSync(normalizedPath).isFile()) { 123 | return false; 124 | } 125 | if (process.platform === 'win32') { 126 | const pathExt = process.env.PATHEXT; 127 | const extname = path.extname(normalizedPath).toUpperCase(); 128 | 129 | if (extname === '' || !pathExt?.includes(extname)) { 130 | return false; 131 | } 132 | } else { 133 | try { 134 | await fsPromises.access(normalizedPath, fs.constants.X_OK); 135 | } catch { 136 | return false; 137 | } 138 | } 139 | 140 | const isValid = await checkValidMagicNumber(normalizedPath); 141 | 142 | return isValid; 143 | } 144 | 145 | export function updateAnalyzersRoot(ONEAPI_ROOT: string) { 146 | const update = 'Update'; 147 | const skip = 'Skip'; 148 | 149 | const newVtuneRoot = path.join(ONEAPI_ROOT, 'vtune', 'latest'); 150 | const newAdvisorRoot = path.join(ONEAPI_ROOT, 'advisor', 'latest'); 151 | 152 | checkIfPathExist(newVtuneRoot) 153 | .then((isExist) => { 154 | if (!isExist) { 155 | vscode.window.showInformationMessage(`${newVtuneRoot} could not be found.`); 156 | } else { 157 | vscode.window.showInformationMessage('Should this ONEAPI_ROOT update change the root path to VTune?', update, skip) 158 | .then((selection) => { 159 | if (selection === update) { 160 | vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator') 161 | .update('vtune.install-root', newVtuneRoot, vscode.ConfigurationTarget.Global); 162 | } 163 | }); 164 | } 165 | }); 166 | checkIfPathExist(newAdvisorRoot) 167 | .then((isExist) => { 168 | if (!isExist) { 169 | vscode.window.showInformationMessage(`${newAdvisorRoot} could not be found.`); 170 | } else { 171 | const advisorConfiguration = vscode.workspace.getConfiguration('intel-corporation.oneapi-analysis-configurator'); 172 | 173 | vscode.window.showInformationMessage('Should this ONEAPI_ROOT update change the root path to Advisor?', update, skip) 174 | .then((selection) => { 175 | if (selection === update) { 176 | advisorConfiguration.update('advisor.install-root', newAdvisorRoot, vscode.ConfigurationTarget.Global); 177 | } 178 | }); 179 | } 180 | }); 181 | } 182 | 183 | export async function wait(milliseconds: number) { 184 | if (typeof milliseconds !== "number" || milliseconds < 0) { 185 | throw new Error("Invalid input for milliseconds"); 186 | } 187 | 188 | return new Promise((resolve) => { 189 | setTimeout(() => resolve(), milliseconds); 190 | }); 191 | } 192 | 193 | export function isWorkspaceOpen() { 194 | return !!vscode.workspace.workspaceFolders; 195 | } 196 | 197 | export async function getworkspaceFolder(): Promise { 198 | if (vscode.workspace.workspaceFolders?.length === 1) { 199 | return vscode.workspace.workspaceFolders[0]; 200 | } 201 | const selection = await vscode.window.showWorkspaceFolderPick(); 202 | 203 | if (!selection) { 204 | vscode.window.showErrorMessage('Cannot find the working directory.', { modal: true }); 205 | vscode.window.showInformationMessage('Please add one or more working directories and try again.'); 206 | return undefined; // for unit tests 207 | } 208 | return selection; 209 | } 210 | 211 | export async function filter(arr: any[], callback: any) { 212 | // eslint-disable-next-line symbol-description 213 | const fail = Symbol(); 214 | 215 | return (await Promise.all(arr.map(async item => (await callback(item)) ? item : fail))).filter(i => i !== fail); 216 | } 217 | 218 | export function isExtensionInstalled(extensionId: string): boolean { 219 | const envConfExtension = vscode.extensions.getExtension(extensionId); 220 | return !!envConfExtension; 221 | } 222 | 223 | export function propmtToInstallExtension(extensionId: string, message: string) { 224 | vscode.window.showErrorMessage(message, { modal: true }, messages.choiceInstall) 225 | .then((selection) => { 226 | if (selection === messages.choiceInstall) { 227 | vscode.commands.executeCommand('workbench.extensions.installExtension', extensionId); 228 | } 229 | }); 230 | } 231 | -------------------------------------------------------------------------------- /third-party-programs.txt: -------------------------------------------------------------------------------- 1 | This file contains the list of third party software (“third party programs”) 2 | contained in the Intel software and their required notices and/or license 3 | terms. This third party software, even if included with the distribution of 4 | the Intel software, may be governed by separate license terms, including 5 | without limitation, third party license terms, other Intel software license 6 | terms, and open source software license terms. These separate license terms 7 | govern your use of the third party programs as set forth in the 8 | “third-party-programs.txt” or other similarly-named text file. 9 | 10 | Third party programs and their corresponding required notices and/or license 11 | terms are listed below. 12 | 13 | ------------------------------------------------------------- 14 | 1. node-xml2js 15 | Copyright 2010, 2011, 2012, 2013. All rights reserved. 16 | 17 | The MIT License (MIT) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to 21 | deal in the Software without restriction, including without limitation the 22 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 23 | sell copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 34 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 35 | IN THE SOFTWARE. 36 | 37 | ------------------------------------------------------------- 38 | 39 | Other names and brands may be claimed as the property of others. -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "lib": [ 7 | "es6" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "strict": true 12 | }, 13 | "exclude": [ 14 | "node_modules", 15 | ".vscode-test", 16 | "test-resources" 17 | ] 18 | } --------------------------------------------------------------------------------