From 88c57b41cd53a2ec7268a6c8b33713d1f8004855 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 21 Apr 2026 19:40:02 +0300 Subject: [PATCH 01/57] made lib compare --- src/opencl/Compare.md | 109 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/opencl/Compare.md diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md new file mode 100644 index 000000000..17c9a5e07 --- /dev/null +++ b/src/opencl/Compare.md @@ -0,0 +1,109 @@ +# Сравнение библиотек для создания механизма конфигурирования +Вся информация взята из репозиториев соответствующих проектов. Дата обращения: 21.04.26. + +## Критерии сравнения + +| Критерий | Метрика | Единицы измерения | +|:---|:---|:---| +| **Зависимости** | количество, суммарный размер | n, MiB | +| **Источники** | CLI (argv) / env / файлы | +/-, форматы | +| **Стандарт C++** | минимальная версия | C++хх | +| **Пакетные менеджеры** | vcpkg / Conan / Conda / apt / brew / pacman | +/- | +| **Способ распространения** | header-only / статическая / динамическая | — | +| **ОС** | Linux / Windows / macOS | +/-, компиляторы | +| **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | +| **Issues** | open, closed/open | n, коэффициент | +| **Сообщество** | GitHub Stars | n | + + + +## Сравнение парсеров командной строки (CLI) + +| Критерий | CLI11 | cxxopts | +|:---|:---:|:---:| +| Зависимости (n, MiB) | 0, 0 | 0, 0 | +| **Источники** | | | +|  CLI (argv) | + | + | +|  env | + | - | +|  Файлы | INI, TOML¹ | - | +| Стандарт C++ | ≥ C++11 | ≥ C++11 | +| **Пакетные менеджеры** | | | +|  vcpkg | + | + | +|  Conan | + | + | +|  Conda | + | ? | +|  apt | ? | ? | +|  brew | ? | + | +|  pacman | ? | ? | +| Способ распространения | header-only | header-only +| **ОС** | | | +|  Linux | + (GCC 4.8+, Clang 3.5+) | + (GCC ≥ 4.9, Clang ≥ 3.1) | +|  Windows | + (MSVC ≥ 2015) | + (MSVC ≥ 2015) | +|  macOS | + (AppleClang 7+) | + (Clang ≥ 3.1 с libc++) | +| **Сообщество** | | | +|  Активность (коммитов/мес) | 4 | 1 | +|  Issues всего | 506 | 307 | +|  Issues closed/open | 9 | 6 | +|  Stars | 4.3k | 4.7k | + + +> ¹ CLI11 поддерживает env с версии 2.4.0, файлы INI/TOML читает как опции командной строки. + +## Парсеры файлов + +| Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | +|:---|:---:|:---:|:---:|:---:| +| Зависимости (n, MiB) | 0, 0 | 0, 0 | 0, 0 | 0, 0 +| **Источники** | | | +|  CLI (argv) | - | - | - | - +|  env | - | - | - | - +|  Файлы | JSON | YAML | TOML | TOML +| Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 +| **Пакетные менеджеры** | | | +|  vcpkg | + | + | + | + +|  Conan | + | + | + | ? +|  Conda | + | + | ? | ? +|  apt | + | + | ? | ? +|  brew | + | + | ? | ? +|  pacman | + | + | ? | ? | +| Способ распространения | header-only | статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only/статическая/динамическая¹ +| **ОС** | | | +|  Linux | + (GCC 4.8–14.2, Clang 3.4–21.0) | + (GCC, Clang) | + (Clang 8+, GCC 8+) | + (GCC, Clang) +|  Windows | + (MSVC 2015–2022) | + (MSVC) | + (MSVC VS2019+) | + (MSVC, MinGW) +|  macOS | + (AppleClang 9.1–16.0) | + (Xcode, AppleClang) | + (AppleClang) | + (AppleClang) +| **Сообщество** | | | +|  Активность (коммитов/мес) | 2 | 9 | 2 | 4 +|  Issues всего | 3271 | 905 | 193 | 194 +|  Issues closed/open | 68 | 3 | 8 | 5 +|  Stars | 49.4k | 15k | 2k | 1.3k + +> ¹ Опционально. + +## Сравнение универсальных инструментов + +| Критерий | Boost +|:---|:---:| +| Зависимости (n, MiB) | 0, ~192 | +| **Источники** | | | +|  CLI (argv) | + | + | +|  env | + | + | +|  Файлы | INI, JSON, XML, TOML | +| Стандарт C++ | ≥ C++11 | ≥ C++11 | +| **Пакетные менеджеры** | | | +|  vcpkg | + | +|  Conan | + | +|  Conda | + | +|  apt | + | +|  brew | + | +|  pacman | + | +| Способ распространения | header-only/статическая/динамическая¹ | +| **ОС** | | | +|  Linux | + (GCC 5+, Clang 3.6+) | +|  Windows | + (MSVC 2015 (vc140)) | +|  macOS | + (AppleClang) | +| **Сообщество** | | | +|  Активность (коммитов/мес) | 12 | +|  Issues всего | 400 | +|  Issues closed/open | 1 | +|  Stars | 9.4k | + +> ¹ Опционально. \ No newline at end of file From f6c9ff12a39f5bf03d106c10295243a238c529da Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Sat, 25 Apr 2026 22:59:16 +0300 Subject: [PATCH 02/57] added more comparison points --- src/opencl/Compare.md | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 17c9a5e07..7a6634642 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -5,9 +5,10 @@ | Критерий | Метрика | Единицы измерения | |:---|:---|:---| -| **Зависимости** | количество, суммарный размер | n, MiB | +| **Зависимости** | наличие | +/- | | **Источники** | CLI (argv) / env / файлы | +/-, форматы | | **Стандарт C++** | минимальная версия | C++хх | +| **Поддерживает стандарт иерархии** | Linux/Windows/MacOS | +/- | | **Пакетные менеджеры** | vcpkg / Conan / Conda / apt / brew / pacman | +/- | | **Способ распространения** | header-only / статическая / динамическая | — | | **ОС** | Linux / Windows / macOS | +/-, компиляторы | @@ -19,14 +20,18 @@ ## Сравнение парсеров командной строки (CLI) -| Критерий | CLI11 | cxxopts | +| Критерий | CLI11 | cxxopts | |:---|:---:|:---:| -| Зависимости (n, MiB) | 0, 0 | 0, 0 | +| Зависимости | - | - | | **Источники** | | | |  CLI (argv) | + | + | |  env | + | - | -|  Файлы | INI, TOML¹ | - | +|  Файлы | - | - | | Стандарт C++ | ≥ C++11 | ≥ C++11 | +| **Поддерживает стандарт иерархии** | | | +|  Linux | + | + | +|  Windows | + | + | +|  MacOS | + | + | | **Пакетные менеджеры** | | | |  vcpkg | + | + | |  Conan | + | + | @@ -46,18 +51,20 @@ |  Stars | 4.3k | 4.7k | -> ¹ CLI11 поддерживает env с версии 2.4.0, файлы INI/TOML читает как опции командной строки. - ## Парсеры файлов | Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | |:---|:---:|:---:|:---:|:---:| -| Зависимости (n, MiB) | 0, 0 | 0, 0 | 0, 0 | 0, 0 +| Зависимости | - | - | - | - | **Источники** | | | |  CLI (argv) | - | - | - | - |  env | - | - | - | - |  Файлы | JSON | YAML | TOML | TOML | Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 +| **Поддерживает стандарт иерархии** | | | +|  Linux | + | + | + | + | +|  Windows | + | + | + | + | +|  MacOS | + | + | + | + | | **Пакетные менеджеры** | | | |  vcpkg | + | + | + | + |  Conan | + | + | + | ? @@ -80,14 +87,18 @@ ## Сравнение универсальных инструментов -| Критерий | Boost +| Критерий | Boost.Program_options |:---|:---:| -| Зависимости (n, MiB) | 0, ~192 | +| Зависимости | + | | **Источники** | | | |  CLI (argv) | + | + | |  env | + | + | -|  Файлы | INI, JSON, XML, TOML | -| Стандарт C++ | ≥ C++11 | ≥ C++11 | +|  Файлы | INI | +| Стандарт C++ | ≥ C++3 | +| **Поддерживает стандарт иерархии** | | | +|  Linux | + | +|  Windows | + | +|  MacOS | + | | **Пакетные менеджеры** | | | |  vcpkg | + | |  Conan | + | @@ -95,10 +106,10 @@ |  apt | + | |  brew | + | |  pacman | + | -| Способ распространения | header-only/статическая/динамическая¹ | +| Способ распространения | статическая/динамическая¹ | | **ОС** | | | |  Linux | + (GCC 5+, Clang 3.6+) | -|  Windows | + (MSVC 2015 (vc140)) | +|  Windows | + (MSVC 2015 (vc140)+) | |  macOS | + (AppleClang) | | **Сообщество** | | | |  Активность (коммитов/мес) | 12 | @@ -106,4 +117,8 @@ |  Issues closed/open | 1 | |  Stars | 9.4k | -> ¹ Опционально. \ No newline at end of file +> ¹ Опционально. + + +## Итог: +По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от Boost.program_options, не требуют зависимостей и являются header-only. \ No newline at end of file From 7419e1637cad00d327c0e9a8ac596258d115be37 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 28 Apr 2026 17:03:26 +0300 Subject: [PATCH 03/57] added list of dependences --- src/opencl/Compare.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 7a6634642..705b1dbca 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -15,6 +15,7 @@ | **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | | **Issues** | open, closed/open | n, коэффициент | | **Сообщество** | GitHub Stars | n | +| **Проходит ли CI** | CI | +/- | @@ -49,6 +50,7 @@ |  Issues всего | 506 | 307 | |  Issues closed/open | 9 | 6 | |  Stars | 4.3k | 4.7k | +| **Проходит ли CI** | CI | + | + | ## Парсеры файлов @@ -82,6 +84,7 @@ |  Issues всего | 3271 | 905 | 193 | 194 |  Issues closed/open | 68 | 3 | 8 | 5 |  Stars | 49.4k | 15k | 2k | 1.3k +| **Проходит ли CI** | CI | + | + | - | + | > ¹ Опционально. @@ -89,7 +92,7 @@ | Критерий | Boost.Program_options |:---|:---:| -| Зависимости | + | +| Зависимости | +¹ | | **Источники** | | | |  CLI (argv) | + | + | |  env | + | + | @@ -106,7 +109,7 @@ |  apt | + | |  brew | + | |  pacman | + | -| Способ распространения | статическая/динамическая¹ | +| Способ распространения | статическая/динамическая² | | **ОС** | | | |  Linux | + (GCC 5+, Clang 3.6+) | |  Windows | + (MSVC 2015 (vc140)+) | @@ -116,8 +119,23 @@ |  Issues всего | 400 | |  Issues closed/open | 1 | |  Stars | 9.4k | +| **Проходит ли CI** | CI | + | -> ¹ Опционально. +> ¹ Список зависимостей: +1. Boost.Any +2. Boost.Bind +3. Boost.Config +4. Boost.Core +5. Boost.Detail +6. Boost.Function +7. Boost.Iterator +8. Boost.Lexical Cast +9. Boost.Smart Ptr +10. Boost.ThrowException +11. Boost.Tokenizer +12. Boost.Type Traits + +> ² Опционально. ## Итог: From 21279b013f3d124a579a75f786f3cc7dcd1f36bf Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 29 Apr 2026 03:48:13 +0300 Subject: [PATCH 04/57] CI -> + --- src/opencl/Compare.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 705b1dbca..e0d144d1e 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -50,7 +50,7 @@ |  Issues всего | 506 | 307 | |  Issues closed/open | 9 | 6 | |  Stars | 4.3k | 4.7k | -| **Проходит ли CI** | CI | + | + | +| **Проходит ли CI** | + | + | + | ## Парсеры файлов @@ -84,7 +84,7 @@ |  Issues всего | 3271 | 905 | 193 | 194 |  Issues closed/open | 68 | 3 | 8 | 5 |  Stars | 49.4k | 15k | 2k | 1.3k -| **Проходит ли CI** | CI | + | + | - | + | +| **Проходит ли CI** | + | + | + | - | + | > ¹ Опционально. @@ -119,7 +119,7 @@ |  Issues всего | 400 | |  Issues closed/open | 1 | |  Stars | 9.4k | -| **Проходит ли CI** | CI | + | +| **Проходит ли CI** | + | + | > ¹ Список зависимостей: 1. Boost.Any From e2a2ad1a96cb9c3a8984f296e292818ed903e9ca Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 29 Apr 2026 03:53:50 +0300 Subject: [PATCH 05/57] Just formatting changes to README --- src/opencl/Compare.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index e0d144d1e..96bfff750 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -122,21 +122,21 @@ | **Проходит ли CI** | + | + | > ¹ Список зависимостей: -1. Boost.Any -2. Boost.Bind -3. Boost.Config -4. Boost.Core -5. Boost.Detail -6. Boost.Function -7. Boost.Iterator -8. Boost.Lexical Cast -9. Boost.Smart Ptr -10. Boost.ThrowException -11. Boost.Tokenizer -12. Boost.Type Traits +> 1. Boost.Any +> 2. Boost.Bind +> 3. Boost.Config +> 4. Boost.Core +> 5. Boost.Detail +> 6. Boost.Function +> 7. Boost.Iterator +> 8. Boost.Lexical Cast +> 9. Boost.Smart Ptr +> 10. Boost.ThrowException +> 11. Boost.Tokenizer +> 12. Boost.Type Traits > ² Опционально. ## Итог: -По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от Boost.program_options, не требуют зависимостей и являются header-only. \ No newline at end of file +По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. \ No newline at end of file From 2ed3b039ffa9ef2d16b59aa24961341eb70642b1 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 4 May 2026 05:53:20 +0300 Subject: [PATCH 06/57] added config params info --- src/opencl/Compare.md | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 96bfff750..77ff795ee 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -139,4 +139,33 @@ ## Итог: -По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. \ No newline at end of file +По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. + + +# Что нужно конфигурировать +1. Выбор платформы +2. Выбор устройства +3. Количество очередей: сейчас создается только 1 очередь +4. Приоритеты очередей +5. Размер линейного аллокатора `DEFAULT_SIZE` +6. Стратегия выбора аллокатора: \ + NVIDIA используют общий аллокатор \ + Все остальные используем линейный аллокатор +7. Характеристики устройтсв:\ + `m_vendor_id` \ + `m_max_cu` \ + `m_default_wgs` \ + `m_max_local_mem` \ + `m_addr_align` \ + пороги `m_max_wgs`, `m_max_cu`, `m_wave_size` +8. Строковые паттерны проверки девайса: возможно только 3 вариаета `m_vendor_name` +6. Дефолтные значения характеристик \ + `m_addr_align` \ + `m_default_wgs` \ + `uint m_wave_size` \ + `uint m_num_of_mem_banks` +7. Суффикс и имя \ + `m_name` \ + `m_suffix ` +8. Тип устройства (чтобы можно было использовать CPU) + `getDevices` \ No newline at end of file From fc33885d6d39fed790e25d6d9a1e7ed27748ed13 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 4 May 2026 22:18:32 +0300 Subject: [PATCH 07/57] added config structure --- src/opencl/Compare.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 77ff795ee..7eaf8c6d3 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -168,4 +168,36 @@ `m_name` \ `m_suffix ` 8. Тип устройства (чтобы можно было использовать CPU) - `getDevices` \ No newline at end of file + `getDevices` + +# Структура конфига (JSON) + +```bash +config: + + "platform": + "selection": + "user_alias": string + "official_name": string + "vendor": "nvidia" | "amd" | "intel" | "img" | "" + "index": int + "priority": int + "fallback": (???) # Нужен ли fallback + + "device": { + "selection": + "user_alias": string + "official_name": string + "type": "gpu" | "cpu" | "accelerator" | "all" + "index": int + "priority": int + "naming": + "accelerator_name" # m_name + "cache_suffix" # m_suffix + "tuning": + "default_work_group_size": int # m_default_wgs + "wave_size": int # m_wave_size + "memory_banks": int # m_num_of_mem_banks + "memory_alignment": int # m_addr_align + "fallback": (???) # Нужен ли fallback +``` \ No newline at end of file From d6809498459635cc7f34f5a24fb0a62e01258776 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 4 May 2026 22:23:01 +0300 Subject: [PATCH 08/57] formatting only --- src/opencl/Compare.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 7eaf8c6d3..6145cccf4 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -188,7 +188,7 @@ config: "selection": "user_alias": string "official_name": string - "type": "gpu" | "cpu" | "accelerator" | "all" + "type": "gpu" | "cpu" "index": int "priority": int "naming": From de27aa71c3eee3f402d965257db681f20fb51b84 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 4 May 2026 22:36:23 +0300 Subject: [PATCH 09/57] added performance parameter --- src/opencl/Compare.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 6145cccf4..3d063e800 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -184,7 +184,7 @@ config: "priority": int "fallback": (???) # Нужен ли fallback - "device": { + "device": "selection": "user_alias": string "official_name": string @@ -200,4 +200,14 @@ config: "memory_banks": int # m_num_of_mem_banks "memory_alignment": int # m_addr_align "fallback": (???) # Нужен ли fallback + + "performance" + "memory" + "linear_allocator_size_mb": int # DEFAULT_SIZE + "allocator_strategy": string # "auto" | "linear" | "general" | "vendor" + "vendor_strategy": + "nvidia": string # "linear" | "general" + "amd": string # "linear" | "general" + "intel": string # "linear" | "general" + "img": strings # "linear" | "general" ``` \ No newline at end of file From e0c9b47137ba531a84748e1924946c31ce71cc6f Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 4 May 2026 22:38:09 +0300 Subject: [PATCH 10/57] formatting only --- src/opencl/Compare.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 3d063e800..0763f1590 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -204,10 +204,10 @@ config: "performance" "memory" "linear_allocator_size_mb": int # DEFAULT_SIZE - "allocator_strategy": string # "auto" | "linear" | "general" | "vendor" + "allocator_strategy": "auto" | "linear" | "general" | "vendor" "vendor_strategy": - "nvidia": string # "linear" | "general" - "amd": string # "linear" | "general" - "intel": string # "linear" | "general" - "img": strings # "linear" | "general" + "nvidia": "linear" | "general" + "amd": "linear" | "general" + "intel": "linear" | "general" + "img": "linear" | "general" ``` \ No newline at end of file From 0b8ca4945d2a6e3b944b098e171bd02a368930fe Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 5 May 2026 18:35:26 +0300 Subject: [PATCH 11/57] formatting --- src/opencl/Compare.md | 52 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 0763f1590..d5ff3481e 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -183,31 +183,29 @@ config: "index": int "priority": int "fallback": (???) # Нужен ли fallback - - "device": - "selection": - "user_alias": string - "official_name": string - "type": "gpu" | "cpu" - "index": int - "priority": int - "naming": - "accelerator_name" # m_name - "cache_suffix" # m_suffix - "tuning": - "default_work_group_size": int # m_default_wgs - "wave_size": int # m_wave_size - "memory_banks": int # m_num_of_mem_banks - "memory_alignment": int # m_addr_align - "fallback": (???) # Нужен ли fallback - - "performance" - "memory" - "linear_allocator_size_mb": int # DEFAULT_SIZE - "allocator_strategy": "auto" | "linear" | "general" | "vendor" - "vendor_strategy": - "nvidia": "linear" | "general" - "amd": "linear" | "general" - "intel": "linear" | "general" - "img": "linear" | "general" + "device": + "selection": + "user_alias": string + "official_name": string + "type": "gpu" | "cpu" + "index": int + "priority": int + "naming": + "accelerator_name" # m_name + "cache_suffix" # m_suffix + "tuning": + "default_work_group_size": int # m_default_wgs + "wave_size": int # m_wave_size + "memory_banks": int # m_num_of_mem_banks + "memory_alignment": int # m_addr_align + "fallback": (???) # Нужен ли fallback + "performance" + "memory" + "linear_allocator_size_mb": int # DEFAULT_SIZE + "allocator_strategy": "auto" | "linear" | "general" | "vendor" + "vendor_strategy": + "nvidia": "linear" | "general" + "amd": "linear" | "general" + "intel": "linear" | "general" + "img": "linear" | "general" ``` \ No newline at end of file From b880e9eb83a28485a7efa538c78f950c518bf754 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 5 May 2026 22:04:53 +0300 Subject: [PATCH 12/57] =?UTF-8?q?added=202=20libs,=20removed=20'=D0=9F?= =?UTF-8?q?=D0=B0=D0=BA=D0=B5=D1=82=D0=BD=D1=8B=D0=B5=20=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=B4=D0=B6=D0=B5=D1=80=D1=8B'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/opencl/Compare.md | 69 +++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 45 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index d5ff3481e..f8bad3444 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -9,7 +9,6 @@ | **Источники** | CLI (argv) / env / файлы | +/-, форматы | | **Стандарт C++** | минимальная версия | C++хх | | **Поддерживает стандарт иерархии** | Linux/Windows/MacOS | +/- | -| **Пакетные менеджеры** | vcpkg / Conan / Conda / apt / brew / pacman | +/- | | **Способ распространения** | header-only / статическая / динамическая | — | | **ОС** | Linux / Windows / macOS | +/-, компиляторы | | **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | @@ -17,6 +16,7 @@ | **Сообщество** | GitHub Stars | n | | **Проходит ли CI** | CI | +/- | +> ? - не указано в README. ## Сравнение парсеров командной строки (CLI) @@ -33,13 +33,6 @@ |  Linux | + | + | |  Windows | + | + | |  MacOS | + | + | -| **Пакетные менеджеры** | | | -|  vcpkg | + | + | -|  Conan | + | + | -|  Conda | + | ? | -|  apt | ? | ? | -|  brew | ? | + | -|  pacman | ? | ? | | Способ распространения | header-only | header-only | **ОС** | | | |  Linux | + (GCC 4.8+, Clang 3.5+) | + (GCC ≥ 4.9, Clang ≥ 3.1) | @@ -50,41 +43,34 @@ |  Issues всего | 506 | 307 | |  Issues closed/open | 9 | 6 | |  Stars | 4.3k | 4.7k | -| **Проходит ли CI** | + | + | + | +| Проходит ли CI | + | + | + | ## Парсеры файлов -| Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | -|:---|:---:|:---:|:---:|:---:| -| Зависимости | - | - | - | - -| **Источники** | | | -|  CLI (argv) | - | - | - | - -|  env | - | - | - | - -|  Файлы | JSON | YAML | TOML | TOML -| Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 -| **Поддерживает стандарт иерархии** | | | -|  Linux | + | + | + | + | -|  Windows | + | + | + | + | -|  MacOS | + | + | + | + | -| **Пакетные менеджеры** | | | -|  vcpkg | + | + | + | + -|  Conan | + | + | + | ? -|  Conda | + | + | ? | ? -|  apt | + | + | ? | ? -|  brew | + | + | ? | ? -|  pacman | + | + | ? | ? | -| Способ распространения | header-only | статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only/статическая/динамическая¹ +| Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | config-cxx | taocpp/config +|:---|:---:|:---:|:---:|:---:|:---:|:---:| +| Зависимости | - | - | - | - | - | - | +| **Источники** | +|  CLI (argv) | - | - | - | - | - | - | +|  env | - | - | - | - | + | + | +|  Файлы | JSON | YAML | TOML | TOML | JSON, YAML, XML | JSON, JAXN | +| Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 | ≥ C++20 | ≥ C++17 | +| **Поддерживает стандарт иерархии** | +|  Linux | + | + | + | + | + | + | +|  Windows | + | + | + | + | + | + | +|  MacOS | + | + | + | + | + | + | +| Способ распространения | header-only | статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only | header-only | | **ОС** | | | -|  Linux | + (GCC 4.8–14.2, Clang 3.4–21.0) | + (GCC, Clang) | + (Clang 8+, GCC 8+) | + (GCC, Clang) -|  Windows | + (MSVC 2015–2022) | + (MSVC) | + (MSVC VS2019+) | + (MSVC, MinGW) -|  macOS | + (AppleClang 9.1–16.0) | + (Xcode, AppleClang) | + (AppleClang) | + (AppleClang) +|  Linux | + (GCC 4.8–14.2, Clang 3.4–21.0) | + (GCC, Clang) | + (Clang 8+, GCC 8+) | + (GCC, Clang) | + (GCC 13+, Clang 16+) | + +|  Windows | + (MSVC 2015–2022) | + (MSVC) | + (MSVC VS2019+) | + (MSVC, MinGW) | + (MSVC 143+ (VS 2022)) | + +|  macOS | + (AppleClang 9.1–16.0) | + (Xcode, AppleClang) | + (AppleClang) | + (AppleClang) | + (AppleClang 16+) | + | **Сообщество** | | | -|  Активность (коммитов/мес) | 2 | 9 | 2 | 4 -|  Issues всего | 3271 | 905 | 193 | 194 -|  Issues closed/open | 68 | 3 | 8 | 5 -|  Stars | 49.4k | 15k | 2k | 1.3k -| **Проходит ли CI** | + | + | + | - | + | +|  Активность (коммитов/мес) | 2 | 9 | 2 | 4 | 2 | 13 | +|  Issues всего | 3271 | 905 | 193 | 194 | 24 | 5 | +|  Issues closed/open | 68 | 3 | 8 | 5 | 0 open | 0 open | +|  Stars | 49.4k | 15k | 2k | 1.3k | 31 | 194 | +| Проходит ли CI | + | + | + | - | + | ? | > ¹ Опционально. @@ -102,13 +88,6 @@ |  Linux | + | |  Windows | + | |  MacOS | + | -| **Пакетные менеджеры** | | | -|  vcpkg | + | -|  Conan | + | -|  Conda | + | -|  apt | + | -|  brew | + | -|  pacman | + | | Способ распространения | статическая/динамическая² | | **ОС** | | | |  Linux | + (GCC 5+, Clang 3.6+) | @@ -119,7 +98,7 @@ |  Issues всего | 400 | |  Issues closed/open | 1 | |  Stars | 9.4k | -| **Проходит ли CI** | + | + | +| Проходит ли CI | + | + | > ¹ Список зависимостей: > 1. Boost.Any From e0c730b9044224d95e85fb3ac15fb9306fd8721f Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 11 May 2026 16:17:12 +0300 Subject: [PATCH 13/57] added SPLA usage scenarios --- src/opencl/Compare.md | 61 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index f8bad3444..2850c0048 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -120,6 +120,61 @@ ## Итог: По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. +# Сценарии использования spla: +**Что важно всем:** возможность выбрать платформу и устройство + +1. Пользователь хочет решить свою задачу + - Неподготовленный пользователь + - важно: + - быстрая настройка через флаги + - что конфигурировать: + - уменьшить количество отладочной информации + - остальное - дефолтные параметры + - Опытный пользователь: + - важно: + - детальная ручная конфигурация параметров через конфигурационный файл + - ускорение вычислений с разреженными данными + - что конфигурировать: + - управление кэшем + - кастомные аллокаторы для разных форматов данных + - управление очередями команд + - Wave size override + - Work-group size + - оптимизация доступа к глобальной памяти + - управление логированием +2. Разработчик spla + - Отладчик, тестировик + - важно: + - верификация корректности работы на разных устройствах + - воспроизводимость ошибок + - что конфигурировать: + - возможность работать только на 1 гпу + - подробное логирование + - отключение кэша для принудительной перекомпиляции + - тестирование на неподдерживаемых вендорах без падения с ошибкой + - Бенчмаркер + - важно: + - минимизация шума при измерениях + - воспроизводимость результатов + - сравнение разных конфигураций + - что конфигурировать: + - профайлинг очередей `CL_QUEUE_PROFILING_ENABLE` + - сбор статистики и уменьшение шума `CLCounterPool` + - количество очередей для измерения параллелизма + - линейный аллокатор для предсказуемости памяти + - Wave size override + - Work-group size + - оптимизация доступа к глобальной памяти + - Расширяющий функциональность + - важно: + - возможность встроить код в существующую инфраструктуру + - чтобы новый код работал на всех устройтсвах + - что конфигурировать: + - включение кэша + - кастомные аллокаторы для разных форматов данных + - управление очередями + - Wave size override + - Work-group size # Что нужно конфигурировать 1. Выбор платформы @@ -187,4 +242,8 @@ config: "amd": "linear" | "general" "intel": "linear" | "general" "img": "linear" | "general" -``` \ No newline at end of file + "queues": + "count": int + +``` + From b5b7580f35e745752840db73949b0da1fc20e93a Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 19 May 2026 04:47:04 +0300 Subject: [PATCH 14/57] making defolt scenario --- src/opencl/Compare.md | 103 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 2850c0048..4baf8f051 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -121,8 +121,109 @@ По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. # Сценарии использования spla: -**Что важно всем:** возможность выбрать платформу и устройство +## Дефолтный сценарий + +Дефолтный сценарий должен решать главную задачу библиотеки: ускорение вычислений. + +### Выбор платформы и устройства + +Сначала следует выбрать наиболее подходящий девайс. Для этого необходимо пройти по всем платформам, собрать все устройства каждой платформы и среди них выбрать лучший. + +Выбранное устройство должно удовлетворять следующим критериям: +1. физически существовать у пользователя + +2. проходить базовые проверки: \ + - запрос размера глобальной памяти \ + - попытка выделить и освободить буфер + +Из всех рабочих и доступных устройств необходимо выбрать наиболее быстрое. Выбор осуществляется по следующей иерархии: + +1. Внешняя GPU (eGPU) + +2. Дискретная GPU (dGPU) + +3. Интегрированная GPU (iGPU) + +4. Запуск на CPU (при отсутствии GPU) + +При наличии нескольких GPU одного типа на каждом из них запускаются микробенчмарки с эталонной задачей, характерной для SPLA. В итоге выбирается GPU, показавшая лучшие результаты, и соответствующая ей платформа. + +Данный подход решает потенциальную проблему, когда девайс указан в OpenCL-платформе, но фактически отсутствует в системе. + +-- + +Нужно ли как-то учитывать параметры платформ? + +Логирование: Выдавать всю информацию (какие стандарты логирования? какая иерархия ошибок?) + +Бенчмарки: \ +Какую задачу прогонять? \ +Как вести замеры? \ +Подбор колтчества очередей: k = (t_вычислений)/ t_общ \ +если k = 0.5 => 1 очередь \ +если k >> 0.5 => ускорять передачу данных? \ +еслм k << 0. => ускорять вычисления? + +как подбирать оптимально \ +пользовательское количество потоков work group size \ +способ аллокации памяти и размер аллокатора +### Настройка очередей команд + +### Логирование + +### Тестовые бенчмарки + + +## Пользователь, который хочет решить свою задачу, используя spla: +### 1. Быстрая настройка основных параметров + +Параметры для конфигурирования: +1. явное указание платформы +2. явное указание устройтсва +3. выбрать количество очередей +4. уменьшить количество отладочной информации до минимума: оставить только критические ошибки +5. выбор аллокатора + +### 2. Замер и сравнение производительности вычислений на разных GPU +Цель пользователя: +1. Минимизация шума при измерениях +2. Воспроизводимость результатов +3. Сравнение разных конфигураций + +Параметры для конфигурирования: +1. явное указание платформы +2. явное указание устройтсва +3. выбрать количество очередей +4. **увеличить количество отладочной информации** +5. выбор аллокатора +6. Wave size override +7. Work-group size +8. профайлинг очередей `CL_QUEUE_PROFILING_ENABLE` +9. сбор статистики и уменьшение шума `CLCounterPool`** + +### 3. Отладка алгоритма GPU +Цель пользователя: +1. верификация корректности работы на разных устройствах +2. воспроизводимость ошибок + +Параметры для конфигурирования: + +### 4. Тестирование GPU +Параметры для конфигурации: + +### 5. Пользователь знает, что некоторые вычисления лучше считаются на GPU +Параметры для конфигурации: + +### 6. Задачи, требующие воспроизводимости +Параметры для конфигурации: + + + + +# Сценарии использования spla: +**Что важно всем:** возможность выбрать платформу и устройство +**Цель:** 1. Пользователь хочет решить свою задачу - Неподготовленный пользователь - важно: From af09acdead6c9dc83f2004bb8960ad2232dd74dd Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 19 May 2026 05:42:31 +0300 Subject: [PATCH 15/57] added 1 question about errors --- src/opencl/Compare.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 4baf8f051..c9c63b8d3 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -168,6 +168,8 @@ пользовательское количество потоков work group size \ способ аллокации памяти и размер аллокатора +Иерархия ошибок? + ### Настройка очередей команд ### Логирование From 627b027af87e7f87f81dcf13dba0842230827f0c Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 1 Jun 2026 09:11:02 +0300 Subject: [PATCH 16/57] added new scenaries --- src/opencl/Compare.md | 187 +++++++++++++----------------------------- 1 file changed, 55 insertions(+), 132 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index c9c63b8d3..acf2feed9 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -121,165 +121,88 @@ По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. # Сценарии использования spla: -## Дефолтный сценарий - -Дефолтный сценарий должен решать главную задачу библиотеки: ускорение вычислений. - -### Выбор платформы и устройства - -Сначала следует выбрать наиболее подходящий девайс. Для этого необходимо пройти по всем платформам, собрать все устройства каждой платформы и среди них выбрать лучший. - -Выбранное устройство должно удовлетворять следующим критериям: -1. физически существовать у пользователя - -2. проходить базовые проверки: \ - - запрос размера глобальной памяти \ - - попытка выделить и освободить буфер - -Из всех рабочих и доступных устройств необходимо выбрать наиболее быстрое. Выбор осуществляется по следующей иерархии: - -1. Внешняя GPU (eGPU) - -2. Дискретная GPU (dGPU) - -3. Интегрированная GPU (iGPU) - -4. Запуск на CPU (при отсутствии GPU) - -При наличии нескольких GPU одного типа на каждом из них запускаются микробенчмарки с эталонной задачей, характерной для SPLA. В итоге выбирается GPU, показавшая лучшие результаты, и соответствующая ей платформа. - -Данный подход решает потенциальную проблему, когда девайс указан в OpenCL-платформе, но фактически отсутствует в системе. - --- - -Нужно ли как-то учитывать параметры платформ? - -Логирование: Выдавать всю информацию (какие стандарты логирования? какая иерархия ошибок?) - -Бенчмарки: \ -Какую задачу прогонять? \ -Как вести замеры? \ -Подбор колтчества очередей: k = (t_вычислений)/ t_общ \ -если k = 0.5 => 1 очередь \ -если k >> 0.5 => ускорять передачу данных? \ -еслм k << 0. => ускорять вычисления? - -как подбирать оптимально \ -пользовательское количество потоков work group size \ -способ аллокации памяти и размер аллокатора - -Иерархия ошибок? - -### Настройка очередей команд - -### Логирование - -### Тестовые бенчмарки - +Библиотека SPLA требует явного конфигурирования. \ +При установке поставляется дефолтный конфиг. Для запуска программы пользователь должен передать библиотеке путь к конфигу (дефолтному или своему) и опционально — идентификатор конфигурации. Если идентификатор не указан, используется конфигурация default. Без конфига библиотека не запускается. ## Пользователь, который хочет решить свою задачу, используя spla: ### 1. Быстрая настройка основных параметров Параметры для конфигурирования: -1. явное указание платформы -2. явное указание устройтсва -3. выбрать количество очередей +1. явное указание платформы `SPLA_OPENCL_PLATFORM` +2. явное указание устройтсва `SPLA_OPENCL_DEVICE` +3. выбрать количество очередей `queues_count` 4. уменьшить количество отладочной информации до минимума: оставить только критические ошибки -5. выбор аллокатора ### 2. Замер и сравнение производительности вычислений на разных GPU -Цель пользователя: -1. Минимизация шума при измерениях -2. Воспроизводимость результатов -3. Сравнение разных конфигураций +Цель пользователя: Сравнение производительности разных девайсов Параметры для конфигурирования: 1. явное указание платформы 2. явное указание устройтсва 3. выбрать количество очередей -4. **увеличить количество отладочной информации** -5. выбор аллокатора -6. Wave size override -7. Work-group size +4. увеличить количество отладочной информации +5. выбор аллокатора `allocator_type` +6. размер для линейного аллокатора `linear_allocator_size` или `block_size` и `block_count` для pool аллокатора +6. `default_wgs` +7. `wave_size` 8. профайлинг очередей `CL_QUEUE_PROFILING_ENABLE` -9. сбор статистики и уменьшение шума `CLCounterPool`** +9. сбор статистики ### 3. Отладка алгоритма GPU Цель пользователя: 1. верификация корректности работы на разных устройствах -2. воспроизводимость ошибок +2. поиск ошибок в алгоритме Параметры для конфигурирования: +1. явное указание платформы +2. явное указание устройтсва +3. выбрать количество очередей +4. увеличить количество отладочной информации +5. очищать кэш при запуске +6. отключение оптимизации при компиляции + ### 4. Тестирование GPU -Параметры для конфигурации: +Цель пользователя: +1. верификация корректности работы устройства +2. поиск ошибок в устройтсве -### 5. Пользователь знает, что некоторые вычисления лучше считаются на GPU Параметры для конфигурации: +1. явное указание платформы +2. явное указание устройтсва +3. выбрать количество очередей +4. увеличить количество отладочной информации -### 6. Задачи, требующие воспроизводимости -Параметры для конфигурации: - +## Разработчик spla: -# Сценарии использования spla: -**Что важно всем:** возможность выбрать платформу и устройство -**Цель:** -1. Пользователь хочет решить свою задачу - - Неподготовленный пользователь - - важно: - - быстрая настройка через флаги - - что конфигурировать: - - уменьшить количество отладочной информации - - остальное - дефолтные параметры - - Опытный пользователь: - - важно: - - детальная ручная конфигурация параметров через конфигурационный файл - - ускорение вычислений с разреженными данными - - что конфигурировать: - - управление кэшем - - кастомные аллокаторы для разных форматов данных - - управление очередями команд - - Wave size override - - Work-group size - - оптимизация доступа к глобальной памяти - - управление логированием -2. Разработчик spla - - Отладчик, тестировик - - важно: - - верификация корректности работы на разных устройствах - - воспроизводимость ошибок - - что конфигурировать: - - возможность работать только на 1 гпу - - подробное логирование - - отключение кэша для принудительной перекомпиляции - - тестирование на неподдерживаемых вендорах без падения с ошибкой - - Бенчмаркер - - важно: - - минимизация шума при измерениях - - воспроизводимость результатов - - сравнение разных конфигураций - - что конфигурировать: - - профайлинг очередей `CL_QUEUE_PROFILING_ENABLE` - - сбор статистики и уменьшение шума `CLCounterPool` - - количество очередей для измерения параллелизма - - линейный аллокатор для предсказуемости памяти - - Wave size override - - Work-group size - - оптимизация доступа к глобальной памяти - - Расширяющий функциональность - - важно: - - возможность встроить код в существующую инфраструктуру - - чтобы новый код работал на всех устройтсвах - - что конфигурировать: - - включение кэша - - кастомные аллокаторы для разных форматов данных - - управление очередями - - Wave size override - - Work-group size - -# Что нужно конфигурировать +### 1. Бенчмаркер + +Цели и параметры конфигурирования аналогичны [сценарию 2](#2-замер-и-сравнение-производительности-вычислений-на-разных-gpu) + + +### 2. Отладчик, тестировик + +Цели и параметры конфигурирования аналогичны [сценарию 3](#3-отладка-алгоритма-gpu) + + + +## Основные дефолтные значения + +платформа: первая платформа \ +девайс: первое устройство \ +queues_count = 1 \ +отладочная информация: критичнеские ошибки \ +аллокатор: general \ +default_wgs: 1\ +wave_size: 1\ +профайлинг: false +сбор статистики: false +очищать кэш при запуске: false +отключение оптимизации при компиляции: false + + # Структура конфига (JSON) From c1b7f2d7be1eec461b5c0de57d7574758a038590 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Thu, 9 Jul 2026 23:04:18 +0500 Subject: [PATCH 17/57] added manual --- src/opencl/Compare.md | 395 ++++++++++++++++++++++++++---------------- 1 file changed, 246 insertions(+), 149 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index acf2feed9..1d51c5016 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -120,156 +120,253 @@ ## Итог: По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. -# Сценарии использования spla: -Библиотека SPLA требует явного конфигурирования. \ -При установке поставляется дефолтный конфиг. Для запуска программы пользователь должен передать библиотеке путь к конфигу (дефолтному или своему) и опционально — идентификатор конфигурации. Если идентификатор не указан, используется конфигурация default. Без конфига библиотека не запускается. - -## Пользователь, который хочет решить свою задачу, используя spla: -### 1. Быстрая настройка основных параметров - -Параметры для конфигурирования: -1. явное указание платформы `SPLA_OPENCL_PLATFORM` -2. явное указание устройтсва `SPLA_OPENCL_DEVICE` -3. выбрать количество очередей `queues_count` -4. уменьшить количество отладочной информации до минимума: оставить только критические ошибки - -### 2. Замер и сравнение производительности вычислений на разных GPU -Цель пользователя: Сравнение производительности разных девайсов - -Параметры для конфигурирования: -1. явное указание платформы -2. явное указание устройтсва -3. выбрать количество очередей -4. увеличить количество отладочной информации -5. выбор аллокатора `allocator_type` -6. размер для линейного аллокатора `linear_allocator_size` или `block_size` и `block_count` для pool аллокатора -6. `default_wgs` -7. `wave_size` -8. профайлинг очередей `CL_QUEUE_PROFILING_ENABLE` -9. сбор статистики - -### 3. Отладка алгоритма GPU -Цель пользователя: -1. верификация корректности работы на разных устройствах -2. поиск ошибок в алгоритме - -Параметры для конфигурирования: -1. явное указание платформы -2. явное указание устройтсва -3. выбрать количество очередей -4. увеличить количество отладочной информации -5. очищать кэш при запуске -6. отключение оптимизации при компиляции - - -### 4. Тестирование GPU -Цель пользователя: -1. верификация корректности работы устройства -2. поиск ошибок в устройтсве - -Параметры для конфигурации: -1. явное указание платформы -2. явное указание устройтсва -3. выбрать количество очередей -4. увеличить количество отладочной информации - - - -## Разработчик spla: - -### 1. Бенчмаркер - -Цели и параметры конфигурирования аналогичны [сценарию 2](#2-замер-и-сравнение-производительности-вычислений-на-разных-gpu) - - -### 2. Отладчик, тестировик - -Цели и параметры конфигурирования аналогичны [сценарию 3](#3-отладка-алгоритма-gpu) - - - -## Основные дефолтные значения - -платформа: первая платформа \ -девайс: первое устройство \ -queues_count = 1 \ -отладочная информация: критичнеские ошибки \ -аллокатор: general \ -default_wgs: 1\ -wave_size: 1\ -профайлинг: false -сбор статистики: false -очищать кэш при запуске: false -отключение оптимизации при компиляции: false - - - -# Структура конфига (JSON) + +# Механизм конфигурирования библиотеки SPLA + +## МАНУАЛ: + +## НАЗВАНИЕ +spla - это фреймворк для математических вычислений с использованием GPU/ускорения + +## СИНОПСИС + +```cpp +#include + + +int main(int argc, char* argv[]) { + + spla_configure(argc, argv); + + return 0; +} +``` +Функция `spla_configure(argc, argv)` необходима для обработки аргументов командной строки, переменных окружения и конфигурационных файлов. + +(будет написана) + +## ОПИСАНИЕ +**spla** - это библиотека с открытым исходным кодом, предоставляющая примитивы разреженной линейной алгебры (матрицы, векторы, скаляры) для математических вычислений с ускорением на GPU. Библиотека поддерживает широкий спектр операций, включая умножение матрицы на вектор, решение систем линейных уравнений и другие алгоритмы разреженной алгебры. + +Для большинства пользователей важно, на каком ускорителе будет запускаться их проект, поэтому необходима возможность явного указания графического ускорителя, OpenCL платформы, количества очередей команд и других параметров, влияющих на производительность и удобство пользователя. + +Библиотека предоставляет механизмы конфигурирования, показанные в порядке убывания приоритета. + +1. Аргументы командной строки 1. +2. Переменные окружения 2. +3. Пользовательский конфигурационный TOML/INI файл 3. +4. Системный конфигурационный TOML/INI файл 3. + +Системный конфигурационный файл имеет наименьший приоритет. \ +Его настройки переопределяются пользовательским конфигурационным файлом, переменными окружения и аргументами командной строки. + +Пользовательский конфигурационный файл имеет приоритет над системным +конфигурационным файлом. \ +Его настройки переопределяются переменными +окружения и аргументами командной строки. + +Переменные окружения имеют приоритет над системным и пользовательским конфигурационными файлами, но уступают аргументам командной строки. + +Аргументы командной строки имеют наивысший приоритет и переопределяют любые настройки, определенные предыдущими способами. + +Если источника конфигурации с меньшим приоритетом не существует, библиотека игнорирует его и переходит к следующему источнику конфигурации. + +Библиотека требует настройки всех обязательных параметров. Без этого будет генерироваться исключение `IncompleteConfigError`.\ +Чтобы исключение не возникало, пользователь должен явно настроить все параметры любым [способом](#configuration_methods). + +> 1 Описание аргументов командной строки приведены в разделе [ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ](#options). \ +2 Описание переменнных окружения приведены в разделе [ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ](#env_variables). \ +3 Шаблон конфигурационного файла с описанием приведен [здесь](#config). + +## ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ +```bash +-sh +--spla-help +``` +Выводит список всех доступных флагов spla с кратким описанием. + +```bash +-sv +--spla-version +``` +Показывает номер версии spla. + +```bash +-ss <путь> +--spla-sconf <путь> +``` +Путь к системному конфигурационному файлу. + +По умолчанию ищет файл в стандартном для данной ОС месте.\ +`/etc/spla/spla.toml` на Linux. \ +`/Library/Preferences/spla/spla.toml` на macOS. \ +`%ProgramData%\spla\spla.toml` на Windows. + +```bash +-su <путь> +--spla-uconf <путь> +``` +Путь к пользовательскому конфигурационному файлу. + +По умолчанию ищет файл в стандартном для данной ОС месте. \ +`~/.config/spla/spla.toml` на Linux. \ +`~/Library/Application Support/spla/spla.toml` на macOS. \ +`%APPDATA%\spla\spla.toml` на Windows. ```bash -config: - - "platform": - "selection": - "user_alias": string - "official_name": string - "vendor": "nvidia" | "amd" | "intel" | "img" | "" - "index": int - "priority": int - "fallback": (???) # Нужен ли fallback - "device": - "selection": - "user_alias": string - "official_name": string - "type": "gpu" | "cpu" - "index": int - "priority": int - "naming": - "accelerator_name" # m_name - "cache_suffix" # m_suffix - "tuning": - "default_work_group_size": int # m_default_wgs - "wave_size": int # m_wave_size - "memory_banks": int # m_num_of_mem_banks - "memory_alignment": int # m_addr_align - "fallback": (???) # Нужен ли fallback - "performance" - "memory" - "linear_allocator_size_mb": int # DEFAULT_SIZE - "allocator_strategy": "auto" | "linear" | "general" | "vendor" - "vendor_strategy": - "nvidia": "linear" | "general" - "amd": "linear" | "general" - "intel": "linear" | "general" - "img": "linear" | "general" - "queues": - "count": int - +-sp <индекс> +--spla-platform <индекс> +``` +Индекс OpenCL платформы. + +```bash +-sd <индекс> +--spla-device <индекс> +``` +Индекс OpenCL-устройства выбранной платформы (GPU/CPU). + +```bash +-sq <число> +--spla-queues <число> +``` +Количество очередей команд. + +Увеличение числа очередей может повысить производительность +за счет параллельного выполнения независимых задач, но слишком большое значение может снизить производительность из-за накладных расходов. \ +Рекомендуется начинать с 1 и экспериментально подбирать оптимальное значение. + +```bash +-sV <уровень> +--spla-verbosity <уровень> +``` +Уровень детализации отладочной информации, выводимой библиотекой. + +| Уровень | Значение | Описание | +|:-------:|:---------|:---------| +| **0** | OFF | Вывод отключён. Сообщения не выводятся. | +| **1** | ERROR | Только критические ошибки. | +| **2** | WARNING | Ошибки и предупреждения. | +| **3** | INFO | Основные этапы работы библиотеки. | + +Что выводится на каждом уровне: + +1. ERROR — `Error`, `NoAcceleration`, `PlatformNotFound`, `DeviceNotFound`, `InvalidState`, `InvalidArgument`, `CompilationError` + +2. WARNING — добавляет к ERROR: `NoValue`, `NotImplemented` + +3. INFO — добавляет к WARNING: `Ok` - информация об инициализации, выборе платформы/устройства, загрузке конфигурации + +```bash +-sp +--spla-profiling +``` +Профилирование очередей команд OpenCL. + +Bключение профилирования добавляет накладные расходы на каждую +операцию и может замедлить выполнение. + +```bash +-sa <тип> +--spla-allocator <тип> +``` +Тип аллокатора памяти для OpenCL-устройства. \ +Ожидает: lineral | general. + +Выбор аллокатора влияет на производительность операций с памятью. +Линейный аллокатор даёт прирост скорости за счёт последовательного выделения, +но может привести к фрагментации памяти при длительной работе. +Общий аллокатор более надёжен, но медленнее. + +```bash +-sS <размер> +--spla-allocator-size <размер> +``` +Размер линейного аллокатора в байтах. + +Увеличение размера позволяет выделять больше памяти за один раз, но увеличивает потребление ресурсов. \ +Этот параметр необходим только при использовании линейного аллокатора `--spla-allocator linear`. +При использовании общего аллокатора можно не указывать. + +Пример: +```bash +./my_program --spla-uconf ~/my_configs/spla.toml --spla-platform 1 -sd 0 --spla-verbosity 3 -sp true --spla-allocator linear --spla-allocator-size 1048576 +``` + +## ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ +Для всех параметров командной строки (кроме --spla-help, --spla-version) существуют аналоги в виде переменных окружения. + +`SPLA_SYSTEM_CONFIG_PATH` \ +Путь к системному конфигурационному файлу. Аналог параметра --spla-sconf. + +`SPLA_USER_CONFIG_PATH` \ +Путь к пользовательскому конфигурационному файлу. Аналог параметра --spla-uconf. + +`SPLA_OPENCL_PLATFORM` \ +Индекс OpenCL платформы. Аналог параметра --spla-platform. + +`SPLA_OPENCL_DEVICE`\ +Индекс OpenCL-устройства на выбранной платформе. +Аналог параметра --spla-device. + +`SPLA_QUEUES`\ +Количество очередей команд OpenCL. +Аналог параметра --spla-queues. + +`SPLA_VERBOSITY`\ +Уровень детализации отладочной информации. +Аналог параметра --spla-verbosity.\ +Принимает значения от 0 до 3. + +`SPLA_PROFILING`\ +Включает профилирование очередей команд OpenCL. +Аналог параметра --spla-profiling. + +`SPLA_ALLOCATOR`\ +Тип аллокатора памяти для OpenCL-устройства. +Аналог параметра --spla-allocator.\ +Принимает значения: linear, general. + +`SPLA_ALLOCATOR_SIZE`\ +Размер линейного аллокатора в байтах. +Аналог параметра --spla-allocator-size.\ +Имеет смысл только при использовании линейного аллокатора. + + +## КОНФИГУРАЦИОННЫЕ ФАЙЛЫ +Для всех аргументов командной строки (кроме --spla-help, --spla-version, --spla-sconf, --spla-uconf) и всех переменных окружения существуют аналоги в виде параметров конфигурационного файла. + +Формат файла - TOML или INI. + +Типы значений. +1. platform = int +2. device = int +3. queues = int +4. verbosity = int +5. profiling = true | false +6. allocator = linear | general +7. allocator_size = int + +Примеры конфигурационных файлов.\ +Этот формат справедлив как для пользовательского, так и для системного конфигурационного файла. + +Формат INI. +```toml +platform = 1 +device = 0 +queues = 4 +verbosity = 2 +profiling = false +allocator = "linear" +allocator_size = 1048576 ``` +Формата ini. +```ini +platform = 1 +device = 0 +queues = 4 +verbosity = 2 +profiling = true +allocator = linear +allocator_size = 1048576 +``` \ No newline at end of file From 8c9ddff705025c412311a609cdd051ba01a2c542 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Fri, 10 Jul 2026 11:07:51 +0500 Subject: [PATCH 18/57] Fixed the incorrect format name in 1 example in CONFIGURATION FALE section (INI -> TOML) --- src/opencl/Compare.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md index 1d51c5016..6df361e57 100644 --- a/src/opencl/Compare.md +++ b/src/opencl/Compare.md @@ -349,7 +349,7 @@ Bключение профилирования добавляет накладн Примеры конфигурационных файлов.\ Этот формат справедлив как для пользовательского, так и для системного конфигурационного файла. -Формат INI. +Формат TOML. ```toml platform = 1 device = 0 @@ -360,7 +360,7 @@ allocator = "linear" allocator_size = 1048576 ``` -Формата ini. +Формата INI. ```ini platform = 1 device = 0 From c90f1857e2062bb0be29cefcc3b46658ddf49ef8 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Sun, 26 Jul 2026 23:03:19 +0500 Subject: [PATCH 19/57] add parsers --- src/opencl/cl_configure.cpp | 301 ++++++++++++++++++++++++++++++++++++ src/opencl/cl_configure.hpp | 65 ++++++++ 2 files changed, 366 insertions(+) create mode 100644 src/opencl/cl_configure.cpp create mode 100644 src/opencl/cl_configure.hpp diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp new file mode 100644 index 000000000..a4c84e5de --- /dev/null +++ b/src/opencl/cl_configure.cpp @@ -0,0 +1,301 @@ +#include "cl_configure.hpp" + +namespace spla { + + Config config_user_and_system; + Config config_cli_and_env; + Config config_final; + + void Config::merge(const Config& source) { + if (source.platform.has_value()) platform = source.platform; + if (source.device.has_value()) device = source.device; + if (source.queues.has_value()) queues = source.queues; + if (source.verbosity.has_value()) verbosity = source.verbosity; + if (source.allocator.has_value()) allocator = source.allocator; + if (source.allocator_size.has_value()) allocator_size = source.allocator_size; + if (source.profiling.has_value()) profiling = source.profiling; + if (source.system_config_path.has_value()) system_config_path = source.system_config_path; + if (source.user_config_path.has_value()) user_config_path = source.user_config_path; + if (source.help.has_value()) help = source.help; + if (source.version.has_value()) version = source.version; + } + + void Config::reset() { + *this = Config{}; + } + + bool Config::has_all_required() const { + return platform.has_value() && + device.has_value() && + queues.has_value() && + profiling.has_value() && + allocator.has_value() && + allocator_size.has_value() && + verbosity.has_value(); + } + + std::string get_spla_version() { + return "SPLA version: 0.0.0"; + } + + std::string get_home_directory() { + #ifdef _WIN32 + const char* home = std::getenv("USERPROFILE"); + if (home) return std::string(home); + + const char* drive = std::getenv("HOMEDRIVE"); + const char* path = std::getenv("HOMEPATH"); + if (drive && path) return std::string(drive) + std::string(path); + return ""; + + #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) + const char* home = std::getenv("HOME"); + if (home) return std::string(home); + + struct passwd* pw = getpwuid(getuid()); + if (pw) return std::string(pw->pw_dir); + return ""; + + #else + #error "Unsupported operating system" + #endif + } + + std::string get_default_system_config_path() { + #ifdef _WIN32 + const char* program_data = std::getenv("PROGRAMDATA"); + if (program_data) { + return std::string(program_data) + "\\spla\\"; + } + return "C:\\ProgramData\\spla\\"; + + #elif defined(__APPLE__) + return "/Library/Application Support/spla/"; + + #elif defined(__linux__) || defined(__unix__) + return "/etc/spla/"; + + #else + #error "Unsupported operating system" + #endif + } + + std::string get_default_user_config_path() { + std::string home = get_home_directory(); + if (home.empty()) { + return ""; + } + + #ifdef _WIN32 + const char* app_data = std::getenv("APPDATA"); + if (app_data) return std::string(app_data) + "\\spla\\"; + return home + "\\AppData\\Roaming\\spla\\"; + + #elif defined(__APPLE__) + return home + "/Library/Application Support/spla/"; + + #elif defined(__linux__) || defined(__unix__) + return home + "/.config/spla/"; + + #else + #error "Unsupported operating system" + #endif + } + + std::string find_first_json_file(const std::string& directory) { + if (directory.empty() || !std::filesystem::exists(directory)) { + return ""; + } + + for (const auto& entry : std::filesystem::directory_iterator(directory)) { + if (entry.is_regular_file()) { + std::string path = entry.path().string(); + if (path.size() >= 5 && + path.compare(path.size() - 5, 5, ".json") == 0) { + return path; + } + } + } + return ""; + } + + ConfigStatus load_from_file(const std::string& path) { + try { + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << path << std::endl; + return ConfigStatus::FileError; + } + + nlohmann::json config_data = nlohmann::json::parse(file); + + if (config_data.contains("platform")) { + config_user_and_system.platform = config_data["platform"].get(); + } + if (config_data.contains("device")) { + config_user_and_system.device = config_data["device"].get(); + } + if (config_data.contains("queues")) { + config_user_and_system.queues = config_data["queues"].get(); + } + if (config_data.contains("verbosity")) { + config_user_and_system.verbosity = config_data["verbosity"].get(); + } + if (config_data.contains("profiling")) { + config_user_and_system.profiling = config_data["profiling"].get(); + } + if (config_data.contains("allocator")) { + config_user_and_system.allocator = config_data["allocator"].get(); + } + if (config_data.contains("allocator_size")) { + config_user_and_system.allocator_size = config_data["allocator_size"].get(); + } + + return ConfigStatus::Ok; + + } catch (const nlohmann::json::exception& e) { + std::cerr << "Error parsing JSON file '" << path << "': " << e.what() << std::endl; + return ConfigStatus::UserOrSystemConfParseError; + } + } + + ConfigStatus parse_system_and_user_conf() { + std::string sys_dir = config_cli_and_env.system_config_path.value_or(get_default_system_config_path()); + std::string user_dir = config_cli_and_env.user_config_path.value_or(get_default_user_config_path()); + + bool file_loaded = false; + + if (sys_dir != "") { + std::string sys_file = find_first_json_file(sys_dir); + if (sys_file != "") { + std::cout << "Loading system config: " << sys_file << std::endl; + load_from_file(sys_file); + file_loaded = true; + } + } + + if (user_dir != "") { + std::string user_file = find_first_json_file(user_dir); + if (user_file != "") { + std::cout << "Loading user config: " << user_file << std::endl; + load_from_file(user_file); + file_loaded = true; + } + } + + if (!file_loaded) { + std::cerr << "Warning: No JSON configuration files found." << std::endl; + } + + return ConfigStatus::Ok; + } + + ConfigStatus parse_cli_and_env(int argc, char** argv) { + CLI::App app{"SPLA configuration"}; + + app.add_flag("-sh,--spla-help", config_cli_and_env.help, "Show help and exit"); + app.add_flag("-sv,--spla-version", config_cli_and_env.version, "Show version and exit"); + + app.add_option("-ss,--spla-sconf", config_cli_and_env.system_config_path, "Path to system configuration file") + ->envname("SPLA_SYSTEM_CONFIG_PATH"); + + app.add_option("-su,--spla-uconf", config_cli_and_env.user_config_path, "Path to user configuration file") + ->envname("SPLA_USER_CONFIG_PATH"); + + app.add_option("-sp,--spla-platform", config_cli_and_env.platform, "OpenCL platform index") + ->envname("SPLA_OPENCL_PLATFORM") + ->check(CLI::PositiveNumber); + + app.add_option("-sd,--spla-device", config_cli_and_env.device, "OpenCL device index") + ->envname("SPLA_OPENCL_DEVICE") + ->check(CLI::PositiveNumber); + + app.add_option("-sq,--spla-queues", config_cli_and_env.queues, "Number of command queues") + ->envname("SPLA_QUEUES") + ->check(CLI::PositiveNumber); + + app.add_flag("-pr,--spla-profiling", config_cli_and_env.profiling, "Enable profiling of command queues") + ->envname("SPLA_PROFILING"); + + app.add_option("-sa,--spla-allocator", config_cli_and_env.allocator, "Allocator type: linear or general") + ->envname("SPLA_ALLOCATOR") + ->check(CLI::IsMember({"linear", "general"})); + + app.add_option("-sS,--spla-allocator-size", config_cli_and_env.allocator_size, "Linear allocator size in bytes") + ->envname("SPLA_ALLOCATOR_SIZE") + ->check(CLI::PositiveNumber); + + app.add_option("-sV,--spla-verbosity", config_cli_and_env.verbosity, "Verbosity level (0-3)") + ->envname("SPLA_VERBOSITY") + ->check(CLI::Range(0, 3)); + + try { + app.parse(argc, argv); + } catch (const CLI::ParseError& e) { + app.exit(e); + return ConfigStatus::CliOrEnvParseError; + } + + if (config_cli_and_env.help) { + std::cout << app.help() << std::endl; + return ConfigStatus::HelpRequested; + } + + if (config_cli_and_env.version) { + std::cout << get_spla_version() << std::endl; + return ConfigStatus::VersionRequested; + } + + return ConfigStatus::Ok; + } + + ConfigStatus validate(){ + + if (!config_final.has_all_required()) { + std::cerr << "Error: Missing required configuration parameters" << std::endl; + std::exit(1); + } + + return ConfigStatus::Ok; + } + + ConfigStatus apply(){ + return ConfigStatus::Ok; + } + + ConfigStatus configure(int argc, char** argv) { + config_user_and_system.reset(); + config_cli_and_env.reset(); + config_final.reset(); + + ConfigStatus status = parse_cli_and_env(argc, argv); + + if (status == ConfigStatus::HelpRequested || status == ConfigStatus::VersionRequested) { + return status; + } + + if (status != ConfigStatus::Ok) { + return status; + } + + status = parse_system_and_user_conf(); + if (status != ConfigStatus::Ok) { + return status; + } + + config_final = config_user_and_system; + config_final.merge(config_cli_and_env); + + status = validate(); + if (status != ConfigStatus::Ok) { + return status; + } + + status = apply(); + if (status != ConfigStatus::Ok) { + return status; + } + + return ConfigStatus::Ok; + } +} \ No newline at end of file diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp new file mode 100644 index 000000000..7e25a7bb2 --- /dev/null +++ b/src/opencl/cl_configure.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +#include "CLI/CLI.hpp" +#include + +#ifdef _WIN32 +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) + #include + #include +#endif + +namespace spla { + + struct Config { + std::optional help; + std::optional version; + std::optional system_config_path; + std::optional user_config_path; + std::optional platform; + std::optional device; + std::optional queues; + std::optional profiling; + std::optional allocator; + std::optional allocator_size; + std::optional verbosity; + + void merge(const Config& source); + void reset(); + bool has_all_required() const; + }; + + enum ConfigStatus { + Ok, + HelpRequested, + VersionRequested, + + CliOrEnvParseError, + UserOrSystemConfParseError, + FileError + }; + + std::string get_spla_version(); + + std::string get_home_directory(); + std::string get_default_system_config_path(); + std::string get_default_user_config_path(); + std::string find_first_json_file(const std::string& directory); + ConfigStatus load_from_file(const std::string& path); + + ConfigStatus parse_cli_and_env(int argc, char** argv); + ConfigStatus parse_system_and_user_conf(); + + ConfigStatus validate(); + ConfigStatus apply(); + + ConfigStatus configure(int argc, char** argv); + + extern Config config_user_and_system; + extern Config config_cli_and_env; + extern Config config_final; + +} \ No newline at end of file From 82028eb48a27de0a3c9f39ee158bd6f12712ce98 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Sun, 26 Jul 2026 23:15:57 +0500 Subject: [PATCH 20/57] fixed formatting errors --- src/opencl/cl_configure.cpp | 92 ++++++++++++++++++------------------- src/opencl/cl_configure.hpp | 31 ++++++------- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index a4c84e5de..1e7368aac 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -39,16 +39,16 @@ namespace spla { } std::string get_home_directory() { - #ifdef _WIN32 +#ifdef _WIN32 const char* home = std::getenv("USERPROFILE"); if (home) return std::string(home); const char* drive = std::getenv("HOMEDRIVE"); - const char* path = std::getenv("HOMEPATH"); + const char* path = std::getenv("HOMEPATH"); if (drive && path) return std::string(drive) + std::string(path); return ""; - #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) const char* home = std::getenv("HOME"); if (home) return std::string(home); @@ -56,28 +56,28 @@ namespace spla { if (pw) return std::string(pw->pw_dir); return ""; - #else - #error "Unsupported operating system" - #endif +#else + #error "Unsupported operating system" +#endif } std::string get_default_system_config_path() { - #ifdef _WIN32 - const char* program_data = std::getenv("PROGRAMDATA"); - if (program_data) { - return std::string(program_data) + "\\spla\\"; - } - return "C:\\ProgramData\\spla\\"; +#ifdef _WIN32 + const char* program_data = std::getenv("PROGRAMDATA"); + if (program_data) { + return std::string(program_data) + "\\spla\\"; + } + return "C:\\ProgramData\\spla\\"; - #elif defined(__APPLE__) - return "/Library/Application Support/spla/"; +#elif defined(__APPLE__) + return "/Library/Application Support/spla/"; - #elif defined(__linux__) || defined(__unix__) - return "/etc/spla/"; +#elif defined(__linux__) || defined(__unix__) + return "/etc/spla/"; - #else - #error "Unsupported operating system" - #endif +#else + #error "Unsupported operating system" +#endif } std::string get_default_user_config_path() { @@ -86,20 +86,20 @@ namespace spla { return ""; } - #ifdef _WIN32 +#ifdef _WIN32 const char* app_data = std::getenv("APPDATA"); if (app_data) return std::string(app_data) + "\\spla\\"; return home + "\\AppData\\Roaming\\spla\\"; - #elif defined(__APPLE__) +#elif defined(__APPLE__) return home + "/Library/Application Support/spla/"; - #elif defined(__linux__) || defined(__unix__) +#elif defined(__linux__) || defined(__unix__) return home + "/.config/spla/"; - #else - #error "Unsupported operating system" - #endif +#else + #error "Unsupported operating system" +#endif } std::string find_first_json_file(const std::string& directory) { @@ -160,7 +160,7 @@ namespace spla { } ConfigStatus parse_system_and_user_conf() { - std::string sys_dir = config_cli_and_env.system_config_path.value_or(get_default_system_config_path()); + std::string sys_dir = config_cli_and_env.system_config_path.value_or(get_default_system_config_path()); std::string user_dir = config_cli_and_env.user_config_path.value_or(get_default_user_config_path()); bool file_loaded = false; @@ -197,37 +197,37 @@ namespace spla { app.add_flag("-sv,--spla-version", config_cli_and_env.version, "Show version and exit"); app.add_option("-ss,--spla-sconf", config_cli_and_env.system_config_path, "Path to system configuration file") - ->envname("SPLA_SYSTEM_CONFIG_PATH"); + ->envname("SPLA_SYSTEM_CONFIG_PATH"); app.add_option("-su,--spla-uconf", config_cli_and_env.user_config_path, "Path to user configuration file") - ->envname("SPLA_USER_CONFIG_PATH"); + ->envname("SPLA_USER_CONFIG_PATH"); app.add_option("-sp,--spla-platform", config_cli_and_env.platform, "OpenCL platform index") - ->envname("SPLA_OPENCL_PLATFORM") - ->check(CLI::PositiveNumber); + ->envname("SPLA_OPENCL_PLATFORM") + ->check(CLI::PositiveNumber); app.add_option("-sd,--spla-device", config_cli_and_env.device, "OpenCL device index") - ->envname("SPLA_OPENCL_DEVICE") - ->check(CLI::PositiveNumber); + ->envname("SPLA_OPENCL_DEVICE") + ->check(CLI::PositiveNumber); app.add_option("-sq,--spla-queues", config_cli_and_env.queues, "Number of command queues") - ->envname("SPLA_QUEUES") - ->check(CLI::PositiveNumber); + ->envname("SPLA_QUEUES") + ->check(CLI::PositiveNumber); app.add_flag("-pr,--spla-profiling", config_cli_and_env.profiling, "Enable profiling of command queues") - ->envname("SPLA_PROFILING"); + ->envname("SPLA_PROFILING"); app.add_option("-sa,--spla-allocator", config_cli_and_env.allocator, "Allocator type: linear or general") - ->envname("SPLA_ALLOCATOR") - ->check(CLI::IsMember({"linear", "general"})); + ->envname("SPLA_ALLOCATOR") + ->check(CLI::IsMember({"linear", "general"})); app.add_option("-sS,--spla-allocator-size", config_cli_and_env.allocator_size, "Linear allocator size in bytes") - ->envname("SPLA_ALLOCATOR_SIZE") - ->check(CLI::PositiveNumber); + ->envname("SPLA_ALLOCATOR_SIZE") + ->check(CLI::PositiveNumber); app.add_option("-sV,--spla-verbosity", config_cli_and_env.verbosity, "Verbosity level (0-3)") - ->envname("SPLA_VERBOSITY") - ->check(CLI::Range(0, 3)); + ->envname("SPLA_VERBOSITY") + ->check(CLI::Range(0, 3)); try { app.parse(argc, argv); @@ -249,7 +249,7 @@ namespace spla { return ConfigStatus::Ok; } - ConfigStatus validate(){ + ConfigStatus validate() { if (!config_final.has_all_required()) { std::cerr << "Error: Missing required configuration parameters" << std::endl; @@ -259,7 +259,7 @@ namespace spla { return ConfigStatus::Ok; } - ConfigStatus apply(){ + ConfigStatus apply() { return ConfigStatus::Ok; } @@ -269,11 +269,11 @@ namespace spla { config_final.reset(); ConfigStatus status = parse_cli_and_env(argc, argv); - + if (status == ConfigStatus::HelpRequested || status == ConfigStatus::VersionRequested) { return status; } - + if (status != ConfigStatus::Ok) { return status; } @@ -298,4 +298,4 @@ namespace spla { return ConfigStatus::Ok; } -} \ No newline at end of file +}// namespace spla \ No newline at end of file diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 7e25a7bb2..921821f2f 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -1,31 +1,31 @@ #pragma once -#include #include +#include #include "CLI/CLI.hpp" #include #ifdef _WIN32 #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) - #include #include + #include #endif namespace spla { struct Config { - std::optional help; - std::optional version; + std::optional help; + std::optional version; std::optional system_config_path; std::optional user_config_path; - std::optional platform; - std::optional device; - std::optional queues; - std::optional profiling; + std::optional platform; + std::optional device; + std::optional queues; + std::optional profiling; std::optional allocator; - std::optional allocator_size; - std::optional verbosity; + std::optional allocator_size; + std::optional verbosity; void merge(const Config& source); void reset(); @@ -44,12 +44,11 @@ namespace spla { std::string get_spla_version(); - std::string get_home_directory(); - std::string get_default_system_config_path(); - std::string get_default_user_config_path(); - std::string find_first_json_file(const std::string& directory); + std::string get_home_directory(); + std::string get_default_system_config_path(); + std::string get_default_user_config_path(); + std::string find_first_json_file(const std::string& directory); ConfigStatus load_from_file(const std::string& path); - ConfigStatus parse_cli_and_env(int argc, char** argv); ConfigStatus parse_system_and_user_conf(); @@ -62,4 +61,4 @@ namespace spla { extern Config config_cli_and_env; extern Config config_final; -} \ No newline at end of file +}// namespace spla \ No newline at end of file From 464aaa0fa698a00f1a3673b99f85dea72c1931ae Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 28 Jul 2026 19:25:11 +0500 Subject: [PATCH 21/57] changed cli parser, file parser, made validate --- src/opencl/cl_configure.cpp | 334 ++++++++++++++++++++++++++---------- src/opencl/cl_configure.hpp | 32 ++-- 2 files changed, 259 insertions(+), 107 deletions(-) diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 1e7368aac..a28f1de2c 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -1,4 +1,5 @@ #include "cl_configure.hpp" +#include "opencl.hpp" namespace spla { @@ -7,37 +8,23 @@ namespace spla { Config config_final; void Config::merge(const Config& source) { + if (source.system_config_path.has_value()) system_config_path = source.system_config_path; + if (source.user_config_path.has_value()) user_config_path = source.user_config_path; if (source.platform.has_value()) platform = source.platform; if (source.device.has_value()) device = source.device; if (source.queues.has_value()) queues = source.queues; - if (source.verbosity.has_value()) verbosity = source.verbosity; + if (source.profiling.has_value()) profiling = source.profiling; if (source.allocator.has_value()) allocator = source.allocator; if (source.allocator_size.has_value()) allocator_size = source.allocator_size; - if (source.profiling.has_value()) profiling = source.profiling; - if (source.system_config_path.has_value()) system_config_path = source.system_config_path; - if (source.user_config_path.has_value()) user_config_path = source.user_config_path; - if (source.help.has_value()) help = source.help; - if (source.version.has_value()) version = source.version; + if (source.default_wgs.has_value()) default_wgs = source.default_wgs; + if (source.wave_size.has_value()) wave_size = source.wave_size; + if (source.verbosity.has_value()) verbosity = source.verbosity; } void Config::reset() { *this = Config{}; } - bool Config::has_all_required() const { - return platform.has_value() && - device.has_value() && - queues.has_value() && - profiling.has_value() && - allocator.has_value() && - allocator_size.has_value() && - verbosity.has_value(); - } - - std::string get_spla_version() { - return "SPLA version: 0.0.0"; - } - std::string get_home_directory() { #ifdef _WIN32 const char* home = std::getenv("USERPROFILE"); @@ -119,129 +106,169 @@ namespace spla { return ""; } - ConfigStatus load_from_file(const std::string& path) { + ConfigStatus load_from_file(const std::string& path, Config& cfg) { try { std::ifstream file(path); if (!file.is_open()) { std::cerr << "Failed to open file: " << path << std::endl; - return ConfigStatus::FileError; + return ConfigStatus::OpenFileError; } nlohmann::json config_data = nlohmann::json::parse(file); if (config_data.contains("platform")) { - config_user_and_system.platform = config_data["platform"].get(); + cfg.platform = config_data["platform"].get(); } if (config_data.contains("device")) { - config_user_and_system.device = config_data["device"].get(); + cfg.device = config_data["device"].get(); } if (config_data.contains("queues")) { - config_user_and_system.queues = config_data["queues"].get(); - } - if (config_data.contains("verbosity")) { - config_user_and_system.verbosity = config_data["verbosity"].get(); + cfg.queues = config_data["queues"].get(); } if (config_data.contains("profiling")) { - config_user_and_system.profiling = config_data["profiling"].get(); + cfg.profiling = config_data["profiling"].get(); } if (config_data.contains("allocator")) { - config_user_and_system.allocator = config_data["allocator"].get(); + cfg.allocator = config_data["allocator"].get(); } if (config_data.contains("allocator_size")) { - config_user_and_system.allocator_size = config_data["allocator_size"].get(); + cfg.allocator_size = config_data["allocator_size"].get(); + } + if (config_data.contains("default_wgs")) { + cfg.default_wgs = config_data["default_wgs"].get(); + } + if (config_data.contains("wave_size")) { + cfg.wave_size = config_data["wave_size"].get(); + } + if (config_data.contains("verbosity")) { + cfg.verbosity = config_data["verbosity"].get(); } return ConfigStatus::Ok; } catch (const nlohmann::json::exception& e) { + std::cerr << "Failed to parse config files" << std::endl; std::cerr << "Error parsing JSON file '" << path << "': " << e.what() << std::endl; return ConfigStatus::UserOrSystemConfParseError; } } - ConfigStatus parse_system_and_user_conf() { - std::string sys_dir = config_cli_and_env.system_config_path.value_or(get_default_system_config_path()); - std::string user_dir = config_cli_and_env.user_config_path.value_or(get_default_user_config_path()); + ConfigStatus parse_system_and_user_conf(const Config& cli_env_config, Config& file_config) { + std::string sys_dir = cli_env_config.system_config_path.value_or(get_default_system_config_path()); + std::string user_dir = cli_env_config.user_config_path.value_or(get_default_user_config_path()); - bool file_loaded = false; + ConfigStatus status = ConfigStatus::Ok; if (sys_dir != "") { std::string sys_file = find_first_json_file(sys_dir); if (sys_file != "") { std::cout << "Loading system config: " << sys_file << std::endl; - load_from_file(sys_file); - file_loaded = true; - } - } + status = load_from_file(sys_file, file_config); + if (status == ConfigStatus::UserOrSystemConfParseError) return status; + } else + std::cout << "No system config found in: " << sys_dir << std::endl; + } else + std::cout << "System config directory is not set. Skipping." << std::endl; if (user_dir != "") { std::string user_file = find_first_json_file(user_dir); if (user_file != "") { std::cout << "Loading user config: " << user_file << std::endl; - load_from_file(user_file); - file_loaded = true; - } - } + status = load_from_file(user_file, file_config); + if (status == ConfigStatus::UserOrSystemConfParseError) return status; + } else + std::cout << "No user config found in: " << user_dir << std::endl; + } else + std::cout << "User config directory is not set. Skipping." << std::endl; - if (!file_loaded) { - std::cerr << "Warning: No JSON configuration files found." << std::endl; - } + if (status == ConfigStatus::OpenFileError) return status; return ConfigStatus::Ok; } - ConfigStatus parse_cli_and_env(int argc, char** argv) { + std::string get_spla_version() { + return "SPLA version: 0.0.0"; + } + + ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg) { CLI::App app{"SPLA configuration"}; - app.add_flag("-sh,--spla-help", config_cli_and_env.help, "Show help and exit"); - app.add_flag("-sv,--spla-version", config_cli_and_env.version, "Show version and exit"); + app.add_flag("-sh,--spla-help", cfg.help, "Show help and exit"); + app.add_flag("-sv,--spla-version", cfg.version, "Show version and exit"); - app.add_option("-ss,--spla-sconf", config_cli_and_env.system_config_path, "Path to system configuration file") + app.add_option("-ss,--spla-sconf", cfg.system_config_path, + "Path to system configuration file\n" + "Config key: (not used in config file)") ->envname("SPLA_SYSTEM_CONFIG_PATH"); - app.add_option("-su,--spla-uconf", config_cli_and_env.user_config_path, "Path to user configuration file") + app.add_option("-su,--spla-uconf", cfg.user_config_path, + "Path to user configuration file\n" + "Config key: (not used in config file)") ->envname("SPLA_USER_CONFIG_PATH"); - app.add_option("-sp,--spla-platform", config_cli_and_env.platform, "OpenCL platform index") - ->envname("SPLA_OPENCL_PLATFORM") - ->check(CLI::PositiveNumber); + app.add_option("-sp,--spla-platform", cfg.platform, + "OpenCL platform index\n" + "Config key: platform") + ->envname("SPLA_OPENCL_PLATFORM"); - app.add_option("-sd,--spla-device", config_cli_and_env.device, "OpenCL device index") - ->envname("SPLA_OPENCL_DEVICE") - ->check(CLI::PositiveNumber); + app.add_option("-sd,--spla-device", cfg.device, + "OpenCL device index\n" + "Config key: device") + ->envname("SPLA_OPENCL_DEVICE"); - app.add_option("-sq,--spla-queues", config_cli_and_env.queues, "Number of command queues") - ->envname("SPLA_QUEUES") - ->check(CLI::PositiveNumber); + app.add_option("-sq,--spla-queues", cfg.queues, + "Number of command queues\n" + "Config key: queues") + ->envname("SPLA_QUEUES"); - app.add_flag("-pr,--spla-profiling", config_cli_and_env.profiling, "Enable profiling of command queues") + app.add_flag("-pr,--spla-profiling", cfg.profiling, + "Enable profiling of command queues\n" + "Config key: profiling\n") ->envname("SPLA_PROFILING"); - app.add_option("-sa,--spla-allocator", config_cli_and_env.allocator, "Allocator type: linear or general") - ->envname("SPLA_ALLOCATOR") - ->check(CLI::IsMember({"linear", "general"})); - - app.add_option("-sS,--spla-allocator-size", config_cli_and_env.allocator_size, "Linear allocator size in bytes") - ->envname("SPLA_ALLOCATOR_SIZE") - ->check(CLI::PositiveNumber); - - app.add_option("-sV,--spla-verbosity", config_cli_and_env.verbosity, "Verbosity level (0-3)") - ->envname("SPLA_VERBOSITY") - ->check(CLI::Range(0, 3)); + app.add_option("-sa,--spla-allocator", cfg.allocator, + "Allocator type: linear or general\n" + "Config key: allocator") + ->envname("SPLA_ALLOCATOR"); + + app.add_option("-as,--spla-allocator-size", cfg.allocator_size, + "Linear allocator size in bytes\n" + "Required for 'linear' allocator. Ignored for 'general'.\n" + "Config key: allocator_size") + ->envname("SPLA_ALLOCATOR_SIZE"); + + app.add_option("-dw,--spla-default-wgs", cfg.default_wgs, + "Default work group size\n" + "Config key: default_wgs") + ->envname("SPLA_DEFAULT_WGS"); + + app.add_option("ws,--spla-wave-size", cfg.wave_size, + "Wave size for device\n" + "Config key: wave_size") + ->envname("SPLA_WAVE_SIZE"); + + app.add_option("-sV,--spla-verbosity", cfg.verbosity, + "Verbosity level:\n" + " 0: No output\n" + " 1: Errors only\n" + " 2: Errors + warnings\n" + " 3: All messages (info, warnings, errors)") + ->envname("SPLA_VERBOSITY"); try { app.parse(argc, argv); } catch (const CLI::ParseError& e) { + std::cerr << "Failed to parse CLI/ENV" << std::endl; app.exit(e); return ConfigStatus::CliOrEnvParseError; } - if (config_cli_and_env.help) { + if (cfg.help) { std::cout << app.help() << std::endl; return ConfigStatus::HelpRequested; } - if (config_cli_and_env.version) { + if (cfg.version) { std::cout << get_spla_version() << std::endl; return ConfigStatus::VersionRequested; } @@ -249,17 +276,126 @@ namespace spla { return ConfigStatus::Ok; } - ConfigStatus validate() { - if (!config_final.has_all_required()) { - std::cerr << "Error: Missing required configuration parameters" << std::endl; - std::exit(1); + ConfigStatus check_platform_and_device(int platform_index, int device_index) { + if (platform_index < 0) { + std::cerr << "Error: platform must be >= 0 (got " << platform_index << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + std::vector platforms; + cl::Platform::get(&platforms); + + if (static_cast(platform_index) >= platforms.size()) { + std::cerr << "Error: Platform " << platform_index << " not found" << std::endl; + return ConfigStatus::PlatformNotFound; + } + + if (device_index < 0) { + std::cerr << "Error: device must be >= 0 (got " << device_index << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + std::vector devices; + platforms[platform_index].getDevices(CL_DEVICE_TYPE_ALL, &devices); + + if (static_cast(device_index) >= devices.size()) { + std::cerr << "Error: Device " << device_index << " not found on platform " << platform_index; + std::cerr << ". Available devices: " << devices.size() << std::endl; + return ConfigStatus::DeviceNotFound; + } + + return ConfigStatus::Ok; + } + + + ConfigStatus validate(const Config& cfg) { + + if (!cfg.platform.has_value()) { + std::cerr << "Error: platform is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.device.has_value()) { + std::cerr << "Error: device is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.queues.has_value()) { + std::cerr << "Error: queues is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.profiling.has_value()) { + std::cerr << "Error: profiling is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.allocator.has_value()) { + std::cerr << "Error: allocator is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (cfg.allocator.value() == "linear" && !cfg.allocator_size.has_value()) { + std::cerr << "Error: allocator_size is required for linear allocator" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.default_wgs.has_value()) { + std::cerr << "Error: default wgs is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.wave_size.has_value()) { + std::cerr << "Error: wave size is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.verbosity.has_value()) { + std::cerr << "Error: verbosity is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + + + ConfigStatus status; + + status = check_platform_and_device(*cfg.platform, *cfg.device); + if (status != ConfigStatus::Ok) { + return status; + } + + + if (*cfg.queues <= 0) { + std::cerr << "Error: queues must be > 0 (got " << *cfg.queues << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + + if (*cfg.allocator != "linear" && *cfg.allocator != "general") { + std::cerr << "Error: allocator must be 'linear' or 'general' (got '" << *cfg.allocator << "')" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + if (*cfg.allocator == "linear") { + if (*cfg.allocator_size == 0) { + std::cerr << "Error: allocator_size must be > 0 for linear allocator" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + } + + + if (*cfg.default_wgs <= 0) { + std::cerr << "Error: default_wgs must be > 0 (got " << *cfg.default_wgs << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + if (*cfg.wave_size <= 0) { + std::cerr << "Error: wave_size must be > 0 (got " << *cfg.wave_size << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + + if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { + std::cerr << "Error: verbosity must be between 0 and 3 (got " << *cfg.verbosity << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; } return ConfigStatus::Ok; } - ConfigStatus apply() { + ConfigStatus apply(const Config& cfg) { return ConfigStatus::Ok; } @@ -268,33 +404,41 @@ namespace spla { config_cli_and_env.reset(); config_final.reset(); - ConfigStatus status = parse_cli_and_env(argc, argv); - - if (status == ConfigStatus::HelpRequested || status == ConfigStatus::VersionRequested) { - return status; - } + ConfigStatus status; - if (status != ConfigStatus::Ok) { - return status; + status = parse_cli_and_env(argc, argv, config_cli_and_env); + if (status != ConfigStatus::CliOrEnvParseError) return status; + else { + std::exit(1); } - status = parse_system_and_user_conf(); - if (status != ConfigStatus::Ok) { - return status; + status = parse_system_and_user_conf(config_cli_and_env, config_user_and_system); + if (status != ConfigStatus::UserOrSystemConfParseError) return status; + else { + std::exit(1); } config_final = config_user_and_system; config_final.merge(config_cli_and_env); - status = validate(); + status = validate(config_final); if (status != ConfigStatus::Ok) { - return status; + std::exit(1); } - status = apply(); - if (status != ConfigStatus::Ok) { - return status; - } + std::cout << "Configuration parametrs:" << std::endl; + std::cout << "OpenCL platform index: " << config_final.platform.value() << std::endl; + std::cout << "OpenCL device index: " << config_final.device.value() << std::endl; + std::cout << "Queues number: " << config_final.queues.value() << std::endl; + std::cout << "Profiling: " << config_final.profiling.value() << std::endl; + std::cout << "Allocator: " << config_final.allocator.value() << std::endl; + if (config_final.allocator == "linear") std::cout << "Linear allocator size: " << config_final.allocator_size.value() << std::endl; + std::cout << "Wave size: " << config_final.wave_size.value() << std::endl; + std::cout << "Default wgs: " << config_final.default_wgs.value() << std::endl; + std::cout << "Verbosity: " << config_final.verbosity.value() << std::endl; + + status = apply(config_final); + if (status != ConfigStatus::Ok) std::exit(1); return ConfigStatus::Ok; } diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 921821f2f..625037c23 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -25,11 +25,12 @@ namespace spla { std::optional profiling; std::optional allocator; std::optional allocator_size; + std::optional default_wgs; + std::optional wave_size; std::optional verbosity; void merge(const Config& source); void reset(); - bool has_all_required() const; }; enum ConfigStatus { @@ -39,26 +40,33 @@ namespace spla { CliOrEnvParseError, UserOrSystemConfParseError, - FileError + OpenFileError, + + MissedParametrs, + PlatformNotFound, + DeviceNotFound, + InvalidConfigParams }; - std::string get_spla_version(); + extern Config config_user_and_system; + extern Config config_cli_and_env; + extern Config config_final; std::string get_home_directory(); std::string get_default_system_config_path(); std::string get_default_user_config_path(); std::string find_first_json_file(const std::string& directory); - ConfigStatus load_from_file(const std::string& path); - ConfigStatus parse_cli_and_env(int argc, char** argv); - ConfigStatus parse_system_and_user_conf(); + ConfigStatus load_from_file(const std::string& path, Config& cfg); - ConfigStatus validate(); - ConfigStatus apply(); + ConfigStatus parse_system_and_user_conf(const Config& cli_env_config, Config& file_config); - ConfigStatus configure(int argc, char** argv); + std::string get_spla_version(); + ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg); - extern Config config_user_and_system; - extern Config config_cli_and_env; - extern Config config_final; + ConfigStatus check_platform_and_device(int platform_index, int device_index); + ConfigStatus validate(const Config& cfg); + ConfigStatus apply(const Config& cfg); + + ConfigStatus configure(int argc, char** argv); }// namespace spla \ No newline at end of file From f8cea2911a44ccff6db52ef912d018f12a48ff7d Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 28 Jul 2026 20:37:47 +0500 Subject: [PATCH 22/57] changed init --- src/opencl/cl_accelerator.cpp | 154 ++++++++-------------------------- 1 file changed, 34 insertions(+), 120 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 6a7a0517a..1f53fbac6 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -40,168 +41,81 @@ namespace spla { CLAccelerator::~CLAccelerator() = default; Status CLAccelerator::init() { - m_description = "no platform or device"; - const char* spla_opencl_platform = std::getenv(SPLA_OPENCL_PLATFORM); - const char* spla_opencl_device = std::getenv(SPLA_OPENCL_DEVICE); - int platform_index = (spla_opencl_platform ? std::atoi(spla_opencl_platform) : 0); - int device_index = (spla_opencl_device ? std::atoi(spla_opencl_device) : 0); + int index_platform = config_final.platform.value(); + int index_device = config_final.device.value(); + int queues_count = config_final.queues.value(); + bool profiling = config_final.profiling.value_or(false); + std::string allocator_type = config_final.allocator.value(); + size_t lin_alloc_size = config_final.allocator_size.value_or(CLAllocLinear::DEFAULT_SIZE); + int default_wgs = config_final.default_wgs.value_or(64); + int wave_size = config_final.wave_size.value_or(32); + int verbosity = config_final.verbosity.value(); - if (set_platform(platform_index) != Status::Ok) - return Status::PlatformNotFound; - - if (set_device(device_index) != Status::Ok) - return Status::DeviceNotFound; - - if (set_queues_count(1) != Status::Ok) - return Status::Error; + //set_verbosity(verbosity); m_cache = std::make_unique(); - // Output handy info - LOG_MSG(Status::Ok, "Initialize accelerator: " << get_description()); - - return Status::Ok; - } - Status CLAccelerator::set_platform(int index) { std::vector available_platforms; cl::Platform::get(&available_platforms); - if (available_platforms.empty()) { - LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration, check your system runtime"); - return Status::PlatformNotFound; - } - if (available_platforms.size() <= index) { - LOG_MSG(Status::InvalidArgument, "index out of list of available platforms"); - return Status::InvalidArgument; - } - m_counter_pool.reset(); m_alloc_general.reset(); m_alloc_linear.reset(); m_alloc_tmp = nullptr; - m_device = cl::Device(); - m_platform = available_platforms[index]; + m_device = cl::Device(); + m_platform = available_platforms[index_platform]; LOG_MSG(Status::Ok, "select OpenCL platform " << m_platform.getInfo()); - return Status::Ok; - } - Status CLAccelerator::set_device(int index) { std::vector available_devices; m_platform.getDevices(CL_DEVICE_TYPE_GPU, &available_devices); - if (available_devices.empty()) { - LOG_MSG(Status::DeviceNotFound, "no device in selected platform, check your OpenCL runtime"); - return Status::DeviceNotFound; - } - if (available_devices.size() <= index) { - LOG_MSG(Status::DeviceNotFound, "index out of list of available devices"); - return Status::DeviceNotFound; - } - - m_device = available_devices[index]; + m_device = available_devices[index_device]; LOG_MSG(Status::Ok, "select OpenCL device " << m_device.getInfo()); - m_vendor_code.clear(); - m_vendor_name = m_device.getInfo(); - m_vendor_id = m_device.getInfo(); - m_max_cu = m_device.getInfo(); - m_max_wgs = m_device.getInfo(); + m_vendor_name = m_device.getInfo(); + m_vendor_id = m_device.getInfo(); + m_max_cu = m_device.getInfo(); + m_max_wgs = m_device.getInfo(); m_max_local_mem = m_device.getInfo(); - m_addr_align = m_device.getInfo() / 8;// from bits to bytes - - m_is_nvidia = false; - m_is_amd = false; - m_is_intel = false; - m_is_img = false; - - if (m_vendor_name.find("Intel") != std::string::npos || - m_vendor_name.find("intel") != std::string::npos || - m_vendor_name.find("INTEL") != std::string::npos || - m_vendor_id == 32902) { - m_vendor_code = VENDOR_CODE_INTEL; - m_default_wgs = 64; - m_wave_size = 8; - m_is_intel = true; - } - if (m_vendor_name.find("Nvidia") != std::string::npos || - m_vendor_name.find("nvidia") != std::string::npos || - m_vendor_name.find("NVIDIA") != std::string::npos || - m_vendor_id == 4318) { - m_vendor_code = VENDOR_CODE_NVIDIA; - m_default_wgs = 64; - m_wave_size = 32; - m_is_nvidia = true; - } - if (m_vendor_name.find("Amd") != std::string::npos || - m_vendor_name.find("amd") != std::string::npos || - m_vendor_name.find("AMD") != std::string::npos || - m_vendor_name.find("Advanced Micro Devices") != std::string::npos || - m_vendor_name.find("advanced micro devices") != std::string::npos || - m_vendor_name.find("ADVANCED MICRO DEVICES") != std::string::npos) { - m_vendor_code = VENDOR_CODE_AMD; - m_default_wgs = 64; - m_wave_size = 64; - m_is_amd = true; - - // Likely, it is an integrated amd device - if (m_max_wgs <= 256 || m_max_cu == 1) m_wave_size = 16; - } - if (m_vendor_name.find("Imagination Technologies") != std::string::npos || - m_vendor_name.find("IMG") != std::string::npos || - m_vendor_name.find("img") != std::string::npos || - m_vendor_id == 0x1010) { - m_vendor_code = VENDOR_CODE_IMG; - m_default_wgs = 32; - m_wave_size = 32; - m_is_img = true; - } - - if (m_vendor_code.empty()) { - LOG_MSG(Status::Error, "failed to match one of the pre-defined vendors"); - m_default_wgs = 64; - m_wave_size = 8; - } + m_addr_align = m_device.getInfo() / 8; + m_default_wgs = default_wgs; + m_wave_size = wave_size; std::stringstream desc; desc << "OpenCL Acc " << m_platform.getInfo() << " device: " << m_device.getInfo() - << " vendor:" << m_vendor_code << " mcu:" << m_max_cu << " wave:" << m_wave_size << " mwgs:" << m_max_wgs; - m_description = desc.str(); - LOG_MSG(Status::Ok, m_description); - return Status::Ok; - } - Status CLAccelerator::set_queues_count(int count) { m_context = cl::Context(m_device); m_queues.clear(); - m_queues.reserve(count); + m_queues.reserve(queues_count); - for (int i = 0; i < count; i++) { + for (int i = 0; i < queues_count; i++) { cl_command_queue_properties properties = 0; -#ifndef SPLA_RELEASE - properties = CL_QUEUE_PROFILING_ENABLE; -#endif + if (profiling) { + properties |= CL_QUEUE_PROFILING_ENABLE; + } cl::CommandQueue queue(m_context, properties); m_queues.emplace_back(std::move(queue)); } - m_counter_pool = std::make_unique(); + m_counter_pool = std::make_unique(); m_alloc_general = std::make_unique(); - m_alloc_tmp = m_alloc_general.get(); - if (!is_nvidia()) { - m_alloc_linear = std::make_unique(CLAllocLinear::DEFAULT_SIZE, m_addr_align); - m_alloc_tmp = m_alloc_linear.get(); + if (allocator_type == "linear") { + m_alloc_linear = std::make_unique(lin_alloc_size, m_addr_align); + m_alloc_tmp = m_alloc_linear.get(); + } else { + m_alloc_tmp = m_alloc_general.get(); } - LOG_MSG(Status::Ok, "configure " << count << " queues for computations"); + LOG_MSG(Status::Ok, "configure " << queues_count << " queues for computations"); return Status::Ok; } const std::string& CLAccelerator::get_name() { @@ -214,4 +128,4 @@ namespace spla { return m_suffix; } -}// namespace spla +}// namespace spla \ No newline at end of file From 0af14328fd66a4796b603474382875eabd07ef9e Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 29 Jul 2026 22:32:38 +0500 Subject: [PATCH 23/57] made apply() and started changing cl_accelerator.cpp,.hpp + added num_of_mem_banks param --- src/opencl/cl_accelerator.cpp | 203 ++++++++++++++++++++++++++++------ src/opencl/cl_accelerator.hpp | 31 ++++-- src/opencl/cl_configure.cpp | 82 ++++++++++++-- src/opencl/cl_configure.hpp | 5 +- 4 files changed, 272 insertions(+), 49 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 1f53fbac6..8a986e1bd 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include @@ -41,83 +40,225 @@ namespace spla { CLAccelerator::~CLAccelerator() = default; Status CLAccelerator::init() { + m_description = "no platform or device"; + + - int index_platform = config_final.platform.value(); - int index_device = config_final.device.value(); - int queues_count = config_final.queues.value(); - bool profiling = config_final.profiling.value_or(false); - std::string allocator_type = config_final.allocator.value(); - size_t lin_alloc_size = config_final.allocator_size.value_or(CLAllocLinear::DEFAULT_SIZE); - int default_wgs = config_final.default_wgs.value_or(64); - int wave_size = config_final.wave_size.value_or(32); - int verbosity = config_final.verbosity.value(); - //set_verbosity(verbosity); m_cache = std::make_unique(); + LOG_MSG(Status::Ok, "Initialize accelerator: " << get_description()); + + return Status::Ok; + } + + + Status CLAccelerator::set_platform(int index) { std::vector available_platforms; cl::Platform::get(&available_platforms); + if (available_platforms.empty()) { + LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration"); + return Status::PlatformNotFound; + } + + if (index < 0) { + LOG_MSG(Status::InvalidArgument, "platform index must be >= 0 (got " << index << ")"); + return Status::InvalidArgument; + } + + if (available_platforms.size() <= static_cast(index)) { + LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_platforms.size() - 1 << ")"); + return Status::InvalidArgument; + } + m_counter_pool.reset(); m_alloc_general.reset(); m_alloc_linear.reset(); m_alloc_tmp = nullptr; - m_device = cl::Device(); - m_platform = available_platforms[index_platform]; + m_device = cl::Device(); + + m_platform = available_platforms[index]; LOG_MSG(Status::Ok, "select OpenCL platform " << m_platform.getInfo()); + return Status::Ok; + } + + + Status CLAccelerator::set_device(int index) { + m_vendor_code.clear(); + std::vector available_devices; m_platform.getDevices(CL_DEVICE_TYPE_GPU, &available_devices); - m_device = available_devices[index_device]; + if (available_devices.empty()) { + LOG_MSG(Status::DeviceNotFound, "no device to select for OpenCL acceleration"); + return Status::DeviceNotFound; + } + + if (index < 0) { + LOG_MSG(Status::InvalidArgument, "device index must be >= 0 (got " << index << ")"); + return Status::InvalidArgument; + } + + if (available_devices.size() <= static_cast(index)) { + LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_devices.size() - 1 << ")"); + return Status::InvalidArgument; + } + + m_device = available_devices[index]; LOG_MSG(Status::Ok, "select OpenCL device " << m_device.getInfo()); - m_vendor_name = m_device.getInfo(); - m_vendor_id = m_device.getInfo(); - m_max_cu = m_device.getInfo(); - m_max_wgs = m_device.getInfo(); + m_vendor_code.clear(); + m_vendor_name = m_device.getInfo(); + m_vendor_id = m_device.getInfo(); + m_max_cu = m_device.getInfo(); + m_max_wgs = m_device.getInfo(); m_max_local_mem = m_device.getInfo(); - m_addr_align = m_device.getInfo() / 8; + m_addr_align = m_device.getInfo() / 8;// from bits to bytes - m_default_wgs = default_wgs; - m_wave_size = wave_size; + m_is_nvidia = false; + m_is_amd = false; + m_is_intel = false; + m_is_img = false; + + if (m_vendor_name.find("Intel") != std::string::npos || + m_vendor_name.find("intel") != std::string::npos || + m_vendor_name.find("INTEL") != std::string::npos || + m_vendor_id == 32902) { + m_vendor_code = VENDOR_CODE_INTEL; + m_is_intel = true; + } + if (m_vendor_name.find("Nvidia") != std::string::npos || + m_vendor_name.find("nvidia") != std::string::npos || + m_vendor_name.find("NVIDIA") != std::string::npos || + m_vendor_id == 4318) { + m_vendor_code = VENDOR_CODE_NVIDIA; + m_is_nvidia = true; + } + if (m_vendor_name.find("Amd") != std::string::npos || + m_vendor_name.find("amd") != std::string::npos || + m_vendor_name.find("AMD") != std::string::npos || + m_vendor_name.find("Advanced Micro Devices") != std::string::npos || + m_vendor_name.find("advanced micro devices") != std::string::npos || + m_vendor_name.find("ADVANCED MICRO DEVICES") != std::string::npos) { + m_vendor_code = VENDOR_CODE_AMD; + m_is_amd = true; + } + if (m_vendor_name.find("Imagination Technologies") != std::string::npos || + m_vendor_name.find("IMG") != std::string::npos || + m_vendor_name.find("img") != std::string::npos || + m_vendor_id == 0x1010) { + m_vendor_code = VENDOR_CODE_IMG; + m_is_img = true; + } + if (m_vendor_code.empty()) { + LOG_MSG(Status::Error, "failed to match one of the pre-defined vendors"); + } std::stringstream desc; desc << "OpenCL Acc " << m_platform.getInfo() << " device: " << m_device.getInfo() + << " vendor:" << m_vendor_code << " mcu:" << m_max_cu << " wave:" << m_wave_size << " mwgs:" << m_max_wgs; + m_description = desc.str(); + LOG_MSG(Status::Ok, m_description); + return Status::Ok; + } + + Status CLAccelerator::set_profiling(bool enabled) { + m_profiling_enabled = enabled; + LOG_MSG(Status::Ok, "set profiling " << (enabled ? "enabled" : "disabled")); + return Status::Ok; + } + + + Status CLAccelerator::set_queues_count(int count) { + if (count <= 0) { + LOG_MSG(Status::InvalidArgument, "queues count must be > 0 (got " << count << ")"); + return Status::InvalidArgument; + } m_context = cl::Context(m_device); m_queues.clear(); - m_queues.reserve(queues_count); + m_queues.reserve(count); - for (int i = 0; i < queues_count; i++) { + for (int i = 0; i < count; i++) { cl_command_queue_properties properties = 0; - if (profiling) { + if (m_profiling_enabled) { properties |= CL_QUEUE_PROFILING_ENABLE; } cl::CommandQueue queue(m_context, properties); m_queues.emplace_back(std::move(queue)); } - m_counter_pool = std::make_unique(); + m_counter_pool = std::make_unique(); m_alloc_general = std::make_unique(); + m_alloc_tmp = m_alloc_general.get(); + + LOG_MSG(Status::Ok, "configure " << count << " queues for computations" + << " (profiling: " << (m_profiling_enabled ? "ON" : "OFF") << ")"); + return Status::Ok; + } + + + Status CLAccelerator::set_linear_allocator(size_t size) { + if (size == 0) { + LOG_MSG(Status::InvalidArgument, "allocator_size must be > 0 for linear allocator (got " << size << ")"); + return Status::InvalidArgument; + } + m_alloc_linear = std::make_unique(size, m_addr_align); + m_alloc_tmp = m_alloc_linear.get(); + LOG_MSG(Status::Ok, "set linear allocator (size: " << size << " bytes)"); + return Status::Ok; + } - if (allocator_type == "linear") { - m_alloc_linear = std::make_unique(lin_alloc_size, m_addr_align); - m_alloc_tmp = m_alloc_linear.get(); - } else { - m_alloc_tmp = m_alloc_general.get(); + + Status CLAccelerator::set_general_allocator() { + m_alloc_tmp = m_alloc_general.get(); + LOG_MSG(Status::Ok, "set general allocator"); + return Status::Ok; + } + + + Status CLAccelerator::set_default_wgs(int wgs) { + if (wgs <= 0) { + LOG_MSG(Status::InvalidArgument, "default_wgs must be > 0 (got " << wgs << ")"); + return Status::InvalidArgument; + } + m_default_wgs = wgs; + LOG_MSG(Status::Ok, "set default work group size: " << wgs); + return Status::Ok; + } + + + Status CLAccelerator::set_wave_size(int size) { + if (size <= 0) { + LOG_MSG(Status::InvalidArgument, "wave_size must be > 0 (got " << size << ")"); + return Status::InvalidArgument; } + m_wave_size = size; + LOG_MSG(Status::Ok, "set wave size: " << size); + return Status::Ok; + } - LOG_MSG(Status::Ok, "configure " << queues_count << " queues for computations"); + + Status CLAccelerator::set_num_of_mem_banks(int banks) { + if (banks <= 0) { + LOG_MSG(Status::InvalidArgument, "num_of_mem_banks must be > 0 (got " << banks << ")"); + return Status::InvalidArgument; + } + m_num_of_mem_banks = banks; + LOG_MSG(Status::Ok, "set num of mem banks: " << banks); return Status::Ok; } + + const std::string& CLAccelerator::get_name() { return m_name; } diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 52a0497e1..94b2eadba 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -73,10 +74,13 @@ namespace spla { Status init() override; Status set_platform(int index) override; Status set_device(int index) override; + Status set_profiling(bool enabled); Status set_queues_count(int count) override; - const std::string& get_name() override; - const std::string& get_description() override; - const std::string& get_suffix() override; + Status set_linear_allocator(size_t size); + Status set_general_allocator(); + Status set_default_wgs(int wgs); + Status set_wave_size(int size); + Status set_num_of_mem_banks(int banks); cl::Platform& get_platform() { return m_platform; } cl::Device& get_device() { return m_device; } @@ -87,13 +91,18 @@ namespace spla { class CLAllocGeneral* get_alloc_general() { return m_alloc_general.get(); } class CLAlloc* get_alloc_tmp() { return m_alloc_tmp; } - [[nodiscard]] const std::string& get_vendor_name() const { return m_vendor_name; } + const std::string& get_name() override; + const std::string& get_description() override; + const std::string& get_suffix() override; + [[nodiscard]] const std::string& get_vendor_code() const { return m_vendor_code; } + [[nodiscard]] const std::string& get_vendor_name() const { return m_vendor_name; } [[nodiscard]] uint get_vendor_id() const { return m_vendor_id; } [[nodiscard]] uint get_max_cu() const { return m_max_cu; } [[nodiscard]] uint get_max_wgs() const { return m_max_wgs; } [[nodiscard]] uint get_max_local_mem() const { return m_max_local_mem; } [[nodiscard]] uint get_addr_align() const { return m_addr_align; } + [[nodiscard]] bool get_profiling_enabled() const { return m_profiling_enabled; } [[nodiscard]] uint get_default_wgs() const { return m_default_wgs; } [[nodiscard]] uint get_wave_size() const { return m_wave_size; } [[nodiscard]] uint get_num_of_mem_banks() const { return m_num_of_mem_banks; } @@ -106,6 +115,7 @@ namespace spla { cl::Platform m_platform; cl::Device m_device; cl::Context m_context; + ankerl::svector m_queues; std::unique_ptr m_cache; std::unique_ptr m_counter_pool; std::unique_ptr m_alloc_linear; @@ -115,22 +125,23 @@ namespace spla { std::string m_name = "OpenCL"; std::string m_description; std::string m_suffix = "__cl"; - std::string m_vendor_name; + std::string m_vendor_code; + std::string m_vendor_name; uint m_vendor_id = 0; uint m_max_cu = 0; uint m_max_wgs = 0; uint m_max_local_mem = 0; - uint m_addr_align = 128; - uint m_default_wgs = 64; - uint m_wave_size = 32; - uint m_num_of_mem_banks = 32; + uint m_addr_align = 0; + bool m_profiling_enabled = false; // + uint m_default_wgs = 0; // + uint m_wave_size = 0; // + uint m_num_of_mem_banks = 0; // bool m_is_nvidia = false; bool m_is_amd = false; bool m_is_intel = false; bool m_is_img = false; - ankerl::svector m_queues; }; /** diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index a28f1de2c..ad9001d1f 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -1,4 +1,5 @@ #include "cl_configure.hpp" +#include "cl_accelerator.hpp" #include "opencl.hpp" namespace spla { @@ -140,6 +141,9 @@ namespace spla { if (config_data.contains("wave_size")) { cfg.wave_size = config_data["wave_size"].get(); } + if (config_data.contains("num_of_mem_banks")) { + cfg.num_of_mem_banks = config_data["num_of_mem_banks"].get(); + } if (config_data.contains("verbosity")) { cfg.verbosity = config_data["verbosity"].get(); } @@ -247,6 +251,11 @@ namespace spla { "Config key: wave_size") ->envname("SPLA_WAVE_SIZE"); + app.add_option("--spla-mem-banks", config_cli_and_env.num_of_mem_banks, + "Number of memory banks (for optimization)\n" + "Config key: num_of_mem_banks") + ->envname("SPLA_MEM_BANKS"); + app.add_option("-sV,--spla-verbosity", cfg.verbosity, "Verbosity level:\n" " 0: No output\n" @@ -278,6 +287,7 @@ namespace spla { ConfigStatus check_platform_and_device(int platform_index, int device_index) { + if (platform_index < 0) { std::cerr << "Error: platform must be >= 0 (got " << platform_index << ")" << std::endl; return ConfigStatus::InvalidConfigParams; @@ -286,11 +296,17 @@ namespace spla { std::vector platforms; cl::Platform::get(&platforms); + if (platforms.empty()) { + std::cerr << "Error: no platform to select for OpenCL acceleration" << std::endl; + return ConfigStatus::PlatformNotFound; + } + if (static_cast(platform_index) >= platforms.size()) { - std::cerr << "Error: Platform " << platform_index << " not found" << std::endl; + std::cerr << "Error: platform index out of range (got " << platform_index << ", max " << platforms.size() - 1 << ")" << std::endl; return ConfigStatus::PlatformNotFound; } + if (device_index < 0) { std::cerr << "Error: device must be >= 0 (got " << device_index << ")" << std::endl; return ConfigStatus::InvalidConfigParams; @@ -299,9 +315,13 @@ namespace spla { std::vector devices; platforms[platform_index].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) { + std::cerr << "Error: no device to select for OpenCL acceleration" << std::endl; + return ConfigStatus::DeviceNotFound; + } + if (static_cast(device_index) >= devices.size()) { - std::cerr << "Error: Device " << device_index << " not found on platform " << platform_index; - std::cerr << ". Available devices: " << devices.size() << std::endl; + std::cerr << "Error: device index out of range (got " << device_index << ", max " << devices.size() - 1 << ")" << std::endl; return ConfigStatus::DeviceNotFound; } @@ -336,11 +356,15 @@ namespace spla { return ConfigStatus::MissedParametrs; } if (!cfg.default_wgs.has_value()) { - std::cerr << "Error: default wgs is required" << std::endl; + std::cerr << "Error: default_wgs is required" << std::endl; return ConfigStatus::MissedParametrs; } if (!cfg.wave_size.has_value()) { - std::cerr << "Error: wave size is required" << std::endl; + std::cerr << "Error: wave_size is required" << std::endl; + return ConfigStatus::MissedParametrs; + } + if (!cfg.num_of_mem_banks.has_value()) { + std::cerr << "Error: num_of_mem_banks is required" << std::endl; return ConfigStatus::MissedParametrs; } if (!cfg.verbosity.has_value()) { @@ -369,8 +393,8 @@ namespace spla { } if (*cfg.allocator == "linear") { - if (*cfg.allocator_size == 0) { - std::cerr << "Error: allocator_size must be > 0 for linear allocator" << std::endl; + if (*cfg.allocator_size <= 0) { + std::cerr << "Error: allocator_size must be > 0 for linear allocator (got " << *cfg.allocator_size << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } } @@ -386,6 +410,11 @@ namespace spla { return ConfigStatus::InvalidConfigParams; } + if (*cfg.num_of_mem_banks <= 0) { + std::cerr << "Error: num_of_mem_banks must be > 0 (got " << *cfg.num_of_mem_banks << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { std::cerr << "Error: verbosity must be between 0 and 3 (got " << *cfg.verbosity << ")" << std::endl; @@ -395,10 +424,48 @@ namespace spla { return ConfigStatus::Ok; } + ConfigStatus apply(const Config& cfg) { + auto* acc = get_acc_cl(); + if (!acc) { + return ConfigStatus::AcceleratorError; + } + + Status status = acc->set_platform(cfg.platform.value()); + if (status != Status::Ok) { + return ConfigStatus::PlatformNotFound; + } + + status = acc->set_device(cfg.device.value()); + if (status != Status::Ok) { + return ConfigStatus::DeviceNotFound; + } + + acc->set_profiling(cfg.profiling.value()); + + status = acc->set_queues_count(cfg.queues.value()); + if (status != Status::Ok) { + return ConfigStatus::AcceleratorError; + } + + if (cfg.allocator.value() == "linear") { + acc->set_linear_allocator(cfg.allocator_size.value()); + } else { + acc->set_general_allocator(); + } + + acc->set_default_wgs(cfg.default_wgs.value()); + acc->set_wave_size(cfg.wave_size.value()); + acc->set_num_of_mem_banks(cfg.num_of_mem_banks.value()); + + status = acc->init(); + if (status != Status::Ok) { + return ConfigStatus::AcceleratorError; + } return ConfigStatus::Ok; } + ConfigStatus configure(int argc, char** argv) { config_user_and_system.reset(); config_cli_and_env.reset(); @@ -435,6 +502,7 @@ namespace spla { if (config_final.allocator == "linear") std::cout << "Linear allocator size: " << config_final.allocator_size.value() << std::endl; std::cout << "Wave size: " << config_final.wave_size.value() << std::endl; std::cout << "Default wgs: " << config_final.default_wgs.value() << std::endl; + std::cout << "Num of mem banks: " << config_final.num_of_mem_banks.value() << std::endl; std::cout << "Verbosity: " << config_final.verbosity.value() << std::endl; status = apply(config_final); diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 625037c23..5f119a7fa 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -27,6 +27,7 @@ namespace spla { std::optional allocator_size; std::optional default_wgs; std::optional wave_size; + std::optional num_of_mem_banks; std::optional verbosity; void merge(const Config& source); @@ -45,7 +46,9 @@ namespace spla { MissedParametrs, PlatformNotFound, DeviceNotFound, - InvalidConfigParams + InvalidConfigParams, + + AcceleratorError }; extern Config config_user_and_system; From 73045f1b8fa533492c56a4f43a05682aa316e6b0 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 29 Jul 2026 23:28:22 +0500 Subject: [PATCH 24/57] removed apply(), changed init() -> init(conf) --- src/opencl/cl_accelerator.cpp | 48 +++++++++++++++++++++- src/opencl/cl_accelerator.hpp | 2 +- src/opencl/cl_configure.cpp | 76 ++++++----------------------------- src/opencl/cl_configure.hpp | 5 +-- 4 files changed, 61 insertions(+), 70 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 8a986e1bd..727dabb19 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -39,12 +39,56 @@ namespace spla { CLAccelerator::CLAccelerator() = default; CLAccelerator::~CLAccelerator() = default; - Status CLAccelerator::init() { + Status CLAccelerator::init(const Config& cfg) { + + ConfigStatus config_status; + config_status = validate(cfg); + if (config_status != ConfigStatus::Ok) { + std::exit(1); + } + + std::cout << "Configuration parametrs:" << std::endl; + std::cout << "OpenCL platform index: " << cfg.platform.value() << std::endl; + std::cout << "OpenCL device index: " << cfg.device.value() << std::endl; + std::cout << "Queues number: " << cfg.queues.value() << std::endl; + std::cout << "Profiling: " << cfg.profiling.value() << std::endl; + std::cout << "Allocator: " << cfg.allocator.value() << std::endl; + if (cfg.allocator == "linear") std::cout << "Linear allocator size: " << cfg.allocator_size.value() << std::endl; + std::cout << "Wave size: " << cfg.wave_size.value() << std::endl; + std::cout << "Default wgs: " << cfg.default_wgs.value() << std::endl; + std::cout << "Num of mem banks: " << cfg.num_of_mem_banks.value() << std::endl; + std::cout << "Verbosity: " << cfg.verbosity.value() << std::endl; + m_description = "no platform or device"; - + if (set_platform(cfg.platform.value()) != Status::Ok) + return Status::PlatformNotFound; + + if (set_device(cfg.device.value()) != Status::Ok) + return Status::DeviceNotFound; + + if (set_profiling(cfg.profiling.value()) != Status::Ok) + return Status::Error; + + if (set_queues_count(cfg.queues.value()) != Status::Ok) + return Status::Error; + + if (cfg.allocator.value() == "linear") { + if (set_linear_allocator(cfg.allocator_size.value()) != Status::Ok) + return Status::Error; + } else { + if (set_general_allocator() != Status::Ok) + return Status::Error; + } + + if (set_default_wgs(cfg.default_wgs.value()) != Status::Ok) + return Status::Error; + if (set_wave_size(cfg.wave_size.value()) != Status::Ok) + return Status::Error; + if (set_num_of_mem_banks(cfg.num_of_mem_banks.value()) != Status::Ok) + return Status::Error; m_cache = std::make_unique(); diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 94b2eadba..dace84957 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -71,7 +71,7 @@ namespace spla { CLAccelerator(); ~CLAccelerator() override; - Status init() override; + Status init(const Config& cfg) override; Status set_platform(int index) override; Status set_device(int index) override; Status set_profiling(bool enabled); diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index ad9001d1f..8ba4d009b 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -425,62 +425,21 @@ namespace spla { } - ConfigStatus apply(const Config& cfg) { - auto* acc = get_acc_cl(); - if (!acc) { - return ConfigStatus::AcceleratorError; - } - - Status status = acc->set_platform(cfg.platform.value()); - if (status != Status::Ok) { - return ConfigStatus::PlatformNotFound; - } - - status = acc->set_device(cfg.device.value()); - if (status != Status::Ok) { - return ConfigStatus::DeviceNotFound; - } - - acc->set_profiling(cfg.profiling.value()); - - status = acc->set_queues_count(cfg.queues.value()); - if (status != Status::Ok) { - return ConfigStatus::AcceleratorError; - } - - if (cfg.allocator.value() == "linear") { - acc->set_linear_allocator(cfg.allocator_size.value()); - } else { - acc->set_general_allocator(); - } - - acc->set_default_wgs(cfg.default_wgs.value()); - acc->set_wave_size(cfg.wave_size.value()); - acc->set_num_of_mem_banks(cfg.num_of_mem_banks.value()); - - status = acc->init(); - if (status != Status::Ok) { - return ConfigStatus::AcceleratorError; - } - return ConfigStatus::Ok; - } - - ConfigStatus configure(int argc, char** argv) { config_user_and_system.reset(); config_cli_and_env.reset(); config_final.reset(); - ConfigStatus status; + ConfigStatus config_status; - status = parse_cli_and_env(argc, argv, config_cli_and_env); - if (status != ConfigStatus::CliOrEnvParseError) return status; + config_status = parse_cli_and_env(argc, argv, config_cli_and_env); + if (config_status != ConfigStatus::CliOrEnvParseError) return config_status; else { std::exit(1); } - status = parse_system_and_user_conf(config_cli_and_env, config_user_and_system); - if (status != ConfigStatus::UserOrSystemConfParseError) return status; + config_status = parse_system_and_user_conf(config_cli_and_env, config_user_and_system); + if (config_status != ConfigStatus::UserOrSystemConfParseError) return config_status; else { std::exit(1); } @@ -488,26 +447,17 @@ namespace spla { config_final = config_user_and_system; config_final.merge(config_cli_and_env); - status = validate(config_final); - if (status != ConfigStatus::Ok) { + auto* acc = get_acc_cl(); + if (!acc) { std::exit(1); } - std::cout << "Configuration parametrs:" << std::endl; - std::cout << "OpenCL platform index: " << config_final.platform.value() << std::endl; - std::cout << "OpenCL device index: " << config_final.device.value() << std::endl; - std::cout << "Queues number: " << config_final.queues.value() << std::endl; - std::cout << "Profiling: " << config_final.profiling.value() << std::endl; - std::cout << "Allocator: " << config_final.allocator.value() << std::endl; - if (config_final.allocator == "linear") std::cout << "Linear allocator size: " << config_final.allocator_size.value() << std::endl; - std::cout << "Wave size: " << config_final.wave_size.value() << std::endl; - std::cout << "Default wgs: " << config_final.default_wgs.value() << std::endl; - std::cout << "Num of mem banks: " << config_final.num_of_mem_banks.value() << std::endl; - std::cout << "Verbosity: " << config_final.verbosity.value() << std::endl; - - status = apply(config_final); - if (status != ConfigStatus::Ok) std::exit(1); + Status status = acc->init(config_final); + if (status != Status::Ok) { + std::exit(1); + } return ConfigStatus::Ok; } -}// namespace spla \ No newline at end of file +}// namespace spla + diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 5f119a7fa..8364a3a34 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -46,9 +46,7 @@ namespace spla { MissedParametrs, PlatformNotFound, DeviceNotFound, - InvalidConfigParams, - - AcceleratorError + InvalidConfigParams }; extern Config config_user_and_system; @@ -68,7 +66,6 @@ namespace spla { ConfigStatus check_platform_and_device(int platform_index, int device_index); ConfigStatus validate(const Config& cfg); - ConfigStatus apply(const Config& cfg); ConfigStatus configure(int argc, char** argv); From a28e55e416441cf38bb7b02836c6605df6ac738f Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 29 Jul 2026 23:31:40 +0500 Subject: [PATCH 25/57] for formatter only --- src/opencl/cl_accelerator.cpp | 2 +- src/opencl/cl_accelerator.hpp | 39 +++++++++++++++++------------------ src/opencl/cl_configure.cpp | 5 ++--- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 727dabb19..0060d1d3e 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -246,7 +246,7 @@ namespace spla { m_alloc_tmp = m_alloc_general.get(); LOG_MSG(Status::Ok, "configure " << count << " queues for computations" - << " (profiling: " << (m_profiling_enabled ? "ON" : "OFF") << ")"); + << " (profiling: " << (m_profiling_enabled ? "ON" : "OFF") << ")"); return Status::Ok; } diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index dace84957..00aed7200 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -31,8 +31,8 @@ #include #include #include -#include #include +#include #include #include @@ -71,11 +71,11 @@ namespace spla { CLAccelerator(); ~CLAccelerator() override; - Status init(const Config& cfg) override; - Status set_platform(int index) override; - Status set_device(int index) override; - Status set_profiling(bool enabled); - Status set_queues_count(int count) override; + Status init(const Config& cfg) override; + Status set_platform(int index) override; + Status set_device(int index) override; + Status set_profiling(bool enabled); + Status set_queues_count(int count) override; Status set_linear_allocator(size_t size); Status set_general_allocator(); Status set_default_wgs(int wgs); @@ -128,20 +128,19 @@ namespace spla { std::string m_vendor_code; std::string m_vendor_name; - uint m_vendor_id = 0; - uint m_max_cu = 0; - uint m_max_wgs = 0; - uint m_max_local_mem = 0; - uint m_addr_align = 0; - bool m_profiling_enabled = false; // - uint m_default_wgs = 0; // - uint m_wave_size = 0; // - uint m_num_of_mem_banks = 0; // - bool m_is_nvidia = false; - bool m_is_amd = false; - bool m_is_intel = false; - bool m_is_img = false; - + uint m_vendor_id = 0; + uint m_max_cu = 0; + uint m_max_wgs = 0; + uint m_max_local_mem = 0; + uint m_addr_align = 0; + bool m_profiling_enabled = false;// + uint m_default_wgs = 0; // + uint m_wave_size = 0; // + uint m_num_of_mem_banks = 0; // + bool m_is_nvidia = false; + bool m_is_amd = false; + bool m_is_intel = false; + bool m_is_img = false; }; /** diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 8ba4d009b..1e3591bef 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -252,8 +252,8 @@ namespace spla { ->envname("SPLA_WAVE_SIZE"); app.add_option("--spla-mem-banks", config_cli_and_env.num_of_mem_banks, - "Number of memory banks (for optimization)\n" - "Config key: num_of_mem_banks") + "Number of memory banks (for optimization)\n" + "Config key: num_of_mem_banks") ->envname("SPLA_MEM_BANKS"); app.add_option("-sV,--spla-verbosity", cfg.verbosity, @@ -460,4 +460,3 @@ namespace spla { return ConfigStatus::Ok; } }// namespace spla - From 8e333d8aed55a402939ae00b48950fb918c071fd Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 31 Aug 2026 17:27:45 +0300 Subject: [PATCH 26/57] add configuration mechanism --- src/opencl/cl_accelerator.cpp | 179 ++++++++-------------------------- src/opencl/cl_accelerator.hpp | 58 +++++------ src/opencl/cl_configure.cpp | 56 +---------- src/opencl/cl_configure.hpp | 3 - 4 files changed, 65 insertions(+), 231 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 0060d1d3e..b36a7b96a 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -39,81 +39,40 @@ namespace spla { CLAccelerator::CLAccelerator() = default; CLAccelerator::~CLAccelerator() = default; - Status CLAccelerator::init(const Config& cfg) { - - ConfigStatus config_status; - config_status = validate(cfg); - if (config_status != ConfigStatus::Ok) { - std::exit(1); - } - - std::cout << "Configuration parametrs:" << std::endl; - std::cout << "OpenCL platform index: " << cfg.platform.value() << std::endl; - std::cout << "OpenCL device index: " << cfg.device.value() << std::endl; - std::cout << "Queues number: " << cfg.queues.value() << std::endl; - std::cout << "Profiling: " << cfg.profiling.value() << std::endl; - std::cout << "Allocator: " << cfg.allocator.value() << std::endl; - if (cfg.allocator == "linear") std::cout << "Linear allocator size: " << cfg.allocator_size.value() << std::endl; - std::cout << "Wave size: " << cfg.wave_size.value() << std::endl; - std::cout << "Default wgs: " << cfg.default_wgs.value() << std::endl; - std::cout << "Num of mem banks: " << cfg.num_of_mem_banks.value() << std::endl; - std::cout << "Verbosity: " << cfg.verbosity.value() << std::endl; - + Status CLAccelerator::init() { m_description = "no platform or device"; - if (set_platform(cfg.platform.value()) != Status::Ok) + const char* spla_opencl_platform = std::getenv(SPLA_OPENCL_PLATFORM); + const char* spla_opencl_device = std::getenv(SPLA_OPENCL_DEVICE); + int platform_index = (spla_opencl_platform ? std::atoi(spla_opencl_platform) : 0); + int device_index = (spla_opencl_device ? std::atoi(spla_opencl_device) : 0); + + if (set_platform(platform_index) != Status::Ok) return Status::PlatformNotFound; - if (set_device(cfg.device.value()) != Status::Ok) + if (set_device(device_index) != Status::Ok) return Status::DeviceNotFound; - if (set_profiling(cfg.profiling.value()) != Status::Ok) - return Status::Error; - - if (set_queues_count(cfg.queues.value()) != Status::Ok) - return Status::Error; - - if (cfg.allocator.value() == "linear") { - if (set_linear_allocator(cfg.allocator_size.value()) != Status::Ok) - return Status::Error; - } else { - if (set_general_allocator() != Status::Ok) - return Status::Error; - } - - if (set_default_wgs(cfg.default_wgs.value()) != Status::Ok) - return Status::Error; - - if (set_wave_size(cfg.wave_size.value()) != Status::Ok) - return Status::Error; - - if (set_num_of_mem_banks(cfg.num_of_mem_banks.value()) != Status::Ok) + if (set_queues_count(1) != Status::Ok) return Status::Error; m_cache = std::make_unique(); + // Output handy info LOG_MSG(Status::Ok, "Initialize accelerator: " << get_description()); return Status::Ok; } - - Status CLAccelerator::set_platform(int index) { std::vector available_platforms; cl::Platform::get(&available_platforms); if (available_platforms.empty()) { - LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration"); + LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration, check your system runtime"); return Status::PlatformNotFound; } - - if (index < 0) { - LOG_MSG(Status::InvalidArgument, "platform index must be >= 0 (got " << index << ")"); - return Status::InvalidArgument; - } - - if (available_platforms.size() <= static_cast(index)) { - LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_platforms.size() - 1 << ")"); + if (available_platforms.size() <= index) { + LOG_MSG(Status::InvalidArgument, "index out of list of available platforms"); return Status::InvalidArgument; } @@ -122,33 +81,22 @@ namespace spla { m_alloc_linear.reset(); m_alloc_tmp = nullptr; m_device = cl::Device(); - - m_platform = available_platforms[index]; + m_platform = available_platforms[index]; LOG_MSG(Status::Ok, "select OpenCL platform " << m_platform.getInfo()); return Status::Ok; } - - Status CLAccelerator::set_device(int index) { - m_vendor_code.clear(); - std::vector available_devices; m_platform.getDevices(CL_DEVICE_TYPE_GPU, &available_devices); if (available_devices.empty()) { - LOG_MSG(Status::DeviceNotFound, "no device to select for OpenCL acceleration"); + LOG_MSG(Status::DeviceNotFound, "no device in selected platform, check your OpenCL runtime"); return Status::DeviceNotFound; } - - if (index < 0) { - LOG_MSG(Status::InvalidArgument, "device index must be >= 0 (got " << index << ")"); - return Status::InvalidArgument; - } - - if (available_devices.size() <= static_cast(index)) { - LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_devices.size() - 1 << ")"); - return Status::InvalidArgument; + if (available_devices.size() <= index) { + LOG_MSG(Status::DeviceNotFound, "index out of list of available devices"); + return Status::DeviceNotFound; } m_device = available_devices[index]; @@ -172,6 +120,8 @@ namespace spla { m_vendor_name.find("INTEL") != std::string::npos || m_vendor_id == 32902) { m_vendor_code = VENDOR_CODE_INTEL; + m_default_wgs = 64; + m_wave_size = 8; m_is_intel = true; } if (m_vendor_name.find("Nvidia") != std::string::npos || @@ -179,6 +129,8 @@ namespace spla { m_vendor_name.find("NVIDIA") != std::string::npos || m_vendor_id == 4318) { m_vendor_code = VENDOR_CODE_NVIDIA; + m_default_wgs = 64; + m_wave_size = 32; m_is_nvidia = true; } if (m_vendor_name.find("Amd") != std::string::npos || @@ -188,19 +140,30 @@ namespace spla { m_vendor_name.find("advanced micro devices") != std::string::npos || m_vendor_name.find("ADVANCED MICRO DEVICES") != std::string::npos) { m_vendor_code = VENDOR_CODE_AMD; + m_default_wgs = 64; + m_wave_size = 64; m_is_amd = true; + + // Likely, it is an integrated amd device + if (m_max_wgs <= 256 || m_max_cu == 1) m_wave_size = 16; } if (m_vendor_name.find("Imagination Technologies") != std::string::npos || m_vendor_name.find("IMG") != std::string::npos || m_vendor_name.find("img") != std::string::npos || m_vendor_id == 0x1010) { m_vendor_code = VENDOR_CODE_IMG; + m_default_wgs = 32; + m_wave_size = 32; m_is_img = true; } + if (m_vendor_code.empty()) { LOG_MSG(Status::Error, "failed to match one of the pre-defined vendors"); + m_default_wgs = 64; + m_wave_size = 8; } + std::stringstream desc; desc << "OpenCL Acc " << m_platform.getInfo() << " device: " << m_device.getInfo() @@ -212,31 +175,19 @@ namespace spla { m_description = desc.str(); LOG_MSG(Status::Ok, m_description); - return Status::Ok; - } - Status CLAccelerator::set_profiling(bool enabled) { - m_profiling_enabled = enabled; - LOG_MSG(Status::Ok, "set profiling " << (enabled ? "enabled" : "disabled")); return Status::Ok; } - - Status CLAccelerator::set_queues_count(int count) { - if (count <= 0) { - LOG_MSG(Status::InvalidArgument, "queues count must be > 0 (got " << count << ")"); - return Status::InvalidArgument; - } - m_context = cl::Context(m_device); m_queues.clear(); m_queues.reserve(count); for (int i = 0; i < count; i++) { cl_command_queue_properties properties = 0; - if (m_profiling_enabled) { - properties |= CL_QUEUE_PROFILING_ENABLE; - } +#ifndef SPLA_RELEASE + properties = CL_QUEUE_PROFILING_ENABLE; +#endif cl::CommandQueue queue(m_context, properties); m_queues.emplace_back(std::move(queue)); } @@ -245,64 +196,14 @@ namespace spla { m_alloc_general = std::make_unique(); m_alloc_tmp = m_alloc_general.get(); - LOG_MSG(Status::Ok, "configure " << count << " queues for computations" - << " (profiling: " << (m_profiling_enabled ? "ON" : "OFF") << ")"); - return Status::Ok; - } - - - Status CLAccelerator::set_linear_allocator(size_t size) { - if (size == 0) { - LOG_MSG(Status::InvalidArgument, "allocator_size must be > 0 for linear allocator (got " << size << ")"); - return Status::InvalidArgument; + if (!is_nvidia()) { + m_alloc_linear = std::make_unique(CLAllocLinear::DEFAULT_SIZE, m_addr_align); + m_alloc_tmp = m_alloc_linear.get(); } - m_alloc_linear = std::make_unique(size, m_addr_align); - m_alloc_tmp = m_alloc_linear.get(); - LOG_MSG(Status::Ok, "set linear allocator (size: " << size << " bytes)"); - return Status::Ok; - } - - Status CLAccelerator::set_general_allocator() { - m_alloc_tmp = m_alloc_general.get(); - LOG_MSG(Status::Ok, "set general allocator"); + LOG_MSG(Status::Ok, "configure " << count << " queues for computations"); return Status::Ok; } - - - Status CLAccelerator::set_default_wgs(int wgs) { - if (wgs <= 0) { - LOG_MSG(Status::InvalidArgument, "default_wgs must be > 0 (got " << wgs << ")"); - return Status::InvalidArgument; - } - m_default_wgs = wgs; - LOG_MSG(Status::Ok, "set default work group size: " << wgs); - return Status::Ok; - } - - - Status CLAccelerator::set_wave_size(int size) { - if (size <= 0) { - LOG_MSG(Status::InvalidArgument, "wave_size must be > 0 (got " << size << ")"); - return Status::InvalidArgument; - } - m_wave_size = size; - LOG_MSG(Status::Ok, "set wave size: " << size); - return Status::Ok; - } - - - Status CLAccelerator::set_num_of_mem_banks(int banks) { - if (banks <= 0) { - LOG_MSG(Status::InvalidArgument, "num_of_mem_banks must be > 0 (got " << banks << ")"); - return Status::InvalidArgument; - } - m_num_of_mem_banks = banks; - LOG_MSG(Status::Ok, "set num of mem banks: " << banks); - return Status::Ok; - } - - const std::string& CLAccelerator::get_name() { return m_name; } diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 00aed7200..f1f8e761a 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -71,16 +70,13 @@ namespace spla { CLAccelerator(); ~CLAccelerator() override; - Status init(const Config& cfg) override; - Status set_platform(int index) override; - Status set_device(int index) override; - Status set_profiling(bool enabled); - Status set_queues_count(int count) override; - Status set_linear_allocator(size_t size); - Status set_general_allocator(); - Status set_default_wgs(int wgs); - Status set_wave_size(int size); - Status set_num_of_mem_banks(int banks); + Status init() override; + Status set_platform(int index) override; + Status set_device(int index) override; + Status set_queues_count(int count) override; + const std::string& get_name() override; + const std::string& get_description() override; + const std::string& get_suffix() override; cl::Platform& get_platform() { return m_platform; } cl::Device& get_device() { return m_device; } @@ -91,18 +87,13 @@ namespace spla { class CLAllocGeneral* get_alloc_general() { return m_alloc_general.get(); } class CLAlloc* get_alloc_tmp() { return m_alloc_tmp; } - const std::string& get_name() override; - const std::string& get_description() override; - const std::string& get_suffix() override; - - [[nodiscard]] const std::string& get_vendor_code() const { return m_vendor_code; } [[nodiscard]] const std::string& get_vendor_name() const { return m_vendor_name; } + [[nodiscard]] const std::string& get_vendor_code() const { return m_vendor_code; } [[nodiscard]] uint get_vendor_id() const { return m_vendor_id; } [[nodiscard]] uint get_max_cu() const { return m_max_cu; } [[nodiscard]] uint get_max_wgs() const { return m_max_wgs; } [[nodiscard]] uint get_max_local_mem() const { return m_max_local_mem; } [[nodiscard]] uint get_addr_align() const { return m_addr_align; } - [[nodiscard]] bool get_profiling_enabled() const { return m_profiling_enabled; } [[nodiscard]] uint get_default_wgs() const { return m_default_wgs; } [[nodiscard]] uint get_wave_size() const { return m_wave_size; } [[nodiscard]] uint get_num_of_mem_banks() const { return m_num_of_mem_banks; } @@ -115,7 +106,6 @@ namespace spla { cl::Platform m_platform; cl::Device m_device; cl::Context m_context; - ankerl::svector m_queues; std::unique_ptr m_cache; std::unique_ptr m_counter_pool; std::unique_ptr m_alloc_linear; @@ -125,22 +115,22 @@ namespace spla { std::string m_name = "OpenCL"; std::string m_description; std::string m_suffix = "__cl"; - - std::string m_vendor_code; std::string m_vendor_name; - uint m_vendor_id = 0; - uint m_max_cu = 0; - uint m_max_wgs = 0; - uint m_max_local_mem = 0; - uint m_addr_align = 0; - bool m_profiling_enabled = false;// - uint m_default_wgs = 0; // - uint m_wave_size = 0; // - uint m_num_of_mem_banks = 0; // - bool m_is_nvidia = false; - bool m_is_amd = false; - bool m_is_intel = false; - bool m_is_img = false; + std::string m_vendor_code; + uint m_vendor_id = 0; + uint m_max_cu = 0; + uint m_max_wgs = 0; + uint m_max_local_mem = 0; + uint m_addr_align = 128; + uint m_default_wgs = 64; + uint m_wave_size = 32; + uint m_num_of_mem_banks = 32; + bool m_is_nvidia = false; + bool m_is_amd = false; + bool m_is_intel = false; + bool m_is_img = false; + + ankerl::svector m_queues; }; /** @@ -158,4 +148,4 @@ namespace spla { }// namespace spla -#endif//SPLA_CL_ACCELERATOR_HPP +#endif//SPLA_CL_ACCELERATOR_HPP \ No newline at end of file diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 1e3591bef..7233e6c3f 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -17,8 +17,6 @@ namespace spla { if (source.profiling.has_value()) profiling = source.profiling; if (source.allocator.has_value()) allocator = source.allocator; if (source.allocator_size.has_value()) allocator_size = source.allocator_size; - if (source.default_wgs.has_value()) default_wgs = source.default_wgs; - if (source.wave_size.has_value()) wave_size = source.wave_size; if (source.verbosity.has_value()) verbosity = source.verbosity; } @@ -135,15 +133,6 @@ namespace spla { if (config_data.contains("allocator_size")) { cfg.allocator_size = config_data["allocator_size"].get(); } - if (config_data.contains("default_wgs")) { - cfg.default_wgs = config_data["default_wgs"].get(); - } - if (config_data.contains("wave_size")) { - cfg.wave_size = config_data["wave_size"].get(); - } - if (config_data.contains("num_of_mem_banks")) { - cfg.num_of_mem_banks = config_data["num_of_mem_banks"].get(); - } if (config_data.contains("verbosity")) { cfg.verbosity = config_data["verbosity"].get(); } @@ -241,21 +230,6 @@ namespace spla { "Config key: allocator_size") ->envname("SPLA_ALLOCATOR_SIZE"); - app.add_option("-dw,--spla-default-wgs", cfg.default_wgs, - "Default work group size\n" - "Config key: default_wgs") - ->envname("SPLA_DEFAULT_WGS"); - - app.add_option("ws,--spla-wave-size", cfg.wave_size, - "Wave size for device\n" - "Config key: wave_size") - ->envname("SPLA_WAVE_SIZE"); - - app.add_option("--spla-mem-banks", config_cli_and_env.num_of_mem_banks, - "Number of memory banks (for optimization)\n" - "Config key: num_of_mem_banks") - ->envname("SPLA_MEM_BANKS"); - app.add_option("-sV,--spla-verbosity", cfg.verbosity, "Verbosity level:\n" " 0: No output\n" @@ -355,18 +329,6 @@ namespace spla { std::cerr << "Error: allocator_size is required for linear allocator" << std::endl; return ConfigStatus::MissedParametrs; } - if (!cfg.default_wgs.has_value()) { - std::cerr << "Error: default_wgs is required" << std::endl; - return ConfigStatus::MissedParametrs; - } - if (!cfg.wave_size.has_value()) { - std::cerr << "Error: wave_size is required" << std::endl; - return ConfigStatus::MissedParametrs; - } - if (!cfg.num_of_mem_banks.has_value()) { - std::cerr << "Error: num_of_mem_banks is required" << std::endl; - return ConfigStatus::MissedParametrs; - } if (!cfg.verbosity.has_value()) { std::cerr << "Error: verbosity is required" << std::endl; return ConfigStatus::MissedParametrs; @@ -400,22 +362,6 @@ namespace spla { } - if (*cfg.default_wgs <= 0) { - std::cerr << "Error: default_wgs must be > 0 (got " << *cfg.default_wgs << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - if (*cfg.wave_size <= 0) { - std::cerr << "Error: wave_size must be > 0 (got " << *cfg.wave_size << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - if (*cfg.num_of_mem_banks <= 0) { - std::cerr << "Error: num_of_mem_banks must be > 0 (got " << *cfg.num_of_mem_banks << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { std::cerr << "Error: verbosity must be between 0 and 3 (got " << *cfg.verbosity << ")" << std::endl; return ConfigStatus::InvalidConfigParams; @@ -452,7 +398,7 @@ namespace spla { std::exit(1); } - Status status = acc->init(config_final); + Status status = acc->init(); if (status != Status::Ok) { std::exit(1); } diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 8364a3a34..d470fbbfe 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -25,9 +25,6 @@ namespace spla { std::optional profiling; std::optional allocator; std::optional allocator_size; - std::optional default_wgs; - std::optional wave_size; - std::optional num_of_mem_banks; std::optional verbosity; void merge(const Config& source); From c9b84f30eadc920386d2b6bd4a0bc9e7fe19ad1d Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 8 Sep 2026 03:15:46 +0300 Subject: [PATCH 27/57] made UserManual and UserGuide --- src/opencl/LibsCompare.md | 126 ++++++++++++++++++++ src/opencl/UserGuide.md | 107 +++++++++++++++++ src/opencl/UserManual.md | 239 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 472 insertions(+) create mode 100644 src/opencl/LibsCompare.md create mode 100644 src/opencl/UserGuide.md create mode 100644 src/opencl/UserManual.md diff --git a/src/opencl/LibsCompare.md b/src/opencl/LibsCompare.md new file mode 100644 index 000000000..14f5ce656 --- /dev/null +++ b/src/opencl/LibsCompare.md @@ -0,0 +1,126 @@ +# Сравнение библиотек для создания механизма конфигурирования +Вся информация взята из репозиториев соответствующих проектов. Дата обращения: 21.04.26. + +## Критерии сравнения + +| Критерий | Метрика | Единицы измерения | +|:---|:---|:---| +| **Зависимости** | наличие | +/- | +| **Источники** | CLI (argv) / env / файлы | +/-, форматы | +| **Стандарт C++** | минимальная версия | C++хх | +| **Поддерживает стандарт иерархии** | Linux/Windows/MacOS | +/- | +| **Способ распространения** | header-only / статическая / динамическая | — | +| **ОС** | Linux / Windows / macOS | +/-, компиляторы | +| **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | +| **Issues** | open, closed/open | n, коэффициент | +| **Сообщество** | GitHub Stars | n | +| **Проходит ли CI** | CI | +/- | + +> ? - не указано в README. + + +## Сравнение парсеров командной строки (CLI) + +| Критерий | CLI11 | cxxopts | +|:---|:---:|:---:| +| Зависимости | - | - | +| **Источники** | | | +|  CLI (argv) | + | + | +|  env | + | - | +|  Файлы | - | - | +| Стандарт C++ | ≥ C++11 | ≥ C++11 | +| **Поддерживает стандарт иерархии** | | | +|  Linux | + | + | +|  Windows | + | + | +|  MacOS | + | + | +| Способ распространения | header-only | header-only +| **ОС** | | | +|  Linux | + (GCC 4.8+, Clang 3.5+) | + (GCC ≥ 4.9, Clang ≥ 3.1) | +|  Windows | + (MSVC ≥ 2015) | + (MSVC ≥ 2015) | +|  macOS | + (AppleClang 7+) | + (Clang ≥ 3.1 с libc++) | +| **Сообщество** | | | +|  Активность (коммитов/мес) | 4 | 1 | +|  Issues всего | 506 | 307 | +|  Issues closed/open | 9 | 6 | +|  Stars | 4.3k | 4.7k | +| Проходит ли CI | + | + | + | + + +## Парсеры файлов + +| Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | config-cxx | taocpp/config +|:---|:---:|:---:|:---:|:---:|:---:|:---:| +| Зависимости | - | - | - | - | - | - | +| **Источники** | +|  CLI (argv) | - | - | - | - | - | - | +|  env | - | - | - | - | + | + | +|  Файлы | JSON | YAML | TOML | TOML | JSON, YAML, XML | JSON, JAXN | +| Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 | ≥ C++20 | ≥ C++17 | +| **Поддерживает стандарт иерархии** | +|  Linux | + | + | + | + | + | + | +|  Windows | + | + | + | + | + | + | +|  MacOS | + | + | + | + | + | + | +| Способ распространения | header-only | статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only | header-only | +| **ОС** | | | +|  Linux | + (GCC 4.8–14.2, Clang 3.4–21.0) | + (GCC, Clang) | + (Clang 8+, GCC 8+) | + (GCC, Clang) | + (GCC 13+, Clang 16+) | + +|  Windows | + (MSVC 2015–2022) | + (MSVC) | + (MSVC VS2019+) | + (MSVC, MinGW) | + (MSVC 143+ (VS 2022)) | + +|  macOS | + (AppleClang 9.1–16.0) | + (Xcode, AppleClang) | + (AppleClang) | + (AppleClang) | + (AppleClang 16+) | + +| **Сообщество** | | | +|  Активность (коммитов/мес) | 2 | 9 | 2 | 4 | 2 | 13 | +|  Issues всего | 3271 | 905 | 193 | 194 | 24 | 5 | +|  Issues closed/open | 68 | 3 | 8 | 5 | 0 open | 0 open | +|  Stars | 49.4k | 15k | 2k | 1.3k | 31 | 194 | +| Проходит ли CI | + | + | + | - | + | ? | + +> ¹ Опционально. + +## Сравнение универсальных инструментов + +| Критерий | Boost.Program_options +|:---|:---:| +| Зависимости | +¹ | +| **Источники** | | | +|  CLI (argv) | + | + | +|  env | + | + | +|  Файлы | INI | +| Стандарт C++ | ≥ C++3 | +| **Поддерживает стандарт иерархии** | | | +|  Linux | + | +|  Windows | + | +|  MacOS | + | +| Способ распространения | статическая/динамическая² | +| **ОС** | | | +|  Linux | + (GCC 5+, Clang 3.6+) | +|  Windows | + (MSVC 2015 (vc140)+) | +|  macOS | + (AppleClang) | +| **Сообщество** | | | +|  Активность (коммитов/мес) | 12 | +|  Issues всего | 400 | +|  Issues closed/open | 1 | +|  Stars | 9.4k | +| Проходит ли CI | + | + | + +> ¹ Список зависимостей: +> 1. Boost.Any +> 2. Boost.Bind +> 3. Boost.Config +> 4. Boost.Core +> 5. Boost.Detail +> 6. Boost.Function +> 7. Boost.Iterator +> 8. Boost.Lexical Cast +> 9. Boost.Smart Ptr +> 10. Boost.ThrowException +> 11. Boost.Tokenizer +> 12. Boost.Type Traits + +> ² Опционально. + + +### Итог: +По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. + + +# Механизм конфигурирования библиотеки SPLA + +Механизм конфигурирования описывается в разделах: [Мануал пользователя](#UserManual) и [Руководство пользователя](#UserGuide) \ No newline at end of file diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md new file mode 100644 index 000000000..0cdf0428a --- /dev/null +++ b/src/opencl/UserGuide.md @@ -0,0 +1,107 @@ +## РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ + +Здесь представлены основные сценарии использования spla и рекоммендации по поводу ее использования. + + +[Первоначальная настройка для нового пользователя](#scenario1) \ +[Интеграция в существующий проект](#scenario2) \ +[Запуск примеров из репозитория](#scenario3) \ +[Сравнение производительности на различных устройствах](#scenario4) + +## Первоначальная настройка для нового пользователя + +Вы хотите выполнить минимальную настройку spla и получить работоспособное приложение. \ +Вы не знакомы с OpenCL, не знаете индексы своих GPU и не хотите разбираться в тонкостях конфигурации. + +По умолчанию spla требует явной настройки всех параметров. Без этого программа упадёт с ошибкой `IncompleteConfigError`. + +### Решение + +Используйте следующую конфигурацию прямо в коде. Скорее всего эти параметры вам подойдут. + +```cpp +#include + +int main(int argc, char* argv[]) { + Config cfg; + cfg.platform = 0; + cfg.device = 0; + cfg.queues = 1; + cfg.verbosity = 1; + cfg.allocator = "general"; + + init(); + + return 0; +} +``` + + +## Запуск примеров из репозитория + +Вы хотите запустить примеры из репозитория, но не знаете, с какими значениями. + +### Решение + +Используйте переменные окружения со следующими параметрами. Скорее всего они вам подойдут. + +```bash +export SPLA_PLATFORM=0 +export SPLA_DEVICE=0 +export SPLA_QUEUES=1 +export SPLA_PROFILING=true +export SPLA_ALLOCATOR=general +export SPLA_VERBOSITY=1 +``` + + +## Интеграция в существующий проект + +Вы хотите внедрить spla в существующий проект, который уже имеет сложную структуру и обработку аргументов командной строки. + +Вы не хотите: + +- Менять main() ради spla +- Добавлять в код жестко заданные значения +- Переписывать парсер аргументов + +### Решение + +Используйте переменные окружения или конфигурационные файлы. Они не требуют изменения кода. + +**Вариант A: Переменные окружения** \ +Пример конфигурации: + +```bash +export SPLA_PLATFORM=0 +export SPLA_DEVICE=0 +export SPLA_QUEUES=2 +export SPLA_PROFILING=true +export SPLA_ALLOCATOR=general +export SPLA_VERBOSITY=1 +``` +Подходят для разового запуска. + +**Вариант B: Конфигурационный файл** \ +Пример конфигурации: + +```json +{ + "platform": 0, + "device": 0, + "queues": 2, + "profiling": true, + "allocator": "general", + "verbosity": 1 +} +``` +Подходят для многократного запуска. + + +## Сравнение производительности на различных устройствах + +Вы хотите выбрать лучшее устройство для вашей задачи, сравнить производительность CPU vs GPU, разных GPU, разных аллокаторов. + +### РЕШЕНИЕ + +Используйте профилирование --spla-profiling = true diff --git a/src/opencl/UserManual.md b/src/opencl/UserManual.md new file mode 100644 index 000000000..189983e9d --- /dev/null +++ b/src/opencl/UserManual.md @@ -0,0 +1,239 @@ +# МАНУАЛ: + +## НАЗВАНИЕ +spla - это фреймворк для математических вычислений с использованием GPU/ускорения + + +## СИНОПСИС + +```cpp +#include + + +int main(int argc, char* argv[]) { + + configure(argc, argv); + + return 0; +} +``` +Функция `configure(argc, argv)` необходима для обработки аргументов командной строки, переменных окружения и конфигурационных файлов. + + +## ОПИСАНИЕ +**spla** - это библиотека с открытым исходным кодом, предоставляющая примитивы разреженной линейной алгебры (матрицы, векторы, скаляры) для математических вычислений с ускорением на GPU. Библиотека поддерживает широкий спектр операций, включая умножение матрицы на вектор, решение систем линейных уравнений и другие алгоритмы разреженной алгебры. + +Для большинства пользователей важно, на каком ускорителе будет запускаться их проект, поэтому необходима возможность явного указания графического ускорителя, OpenCL платформы, количества очередей команд и других параметров, влияющих на производительность и удобство пользователя. + +Библиотека предоставляет механизмы конфигурирования, показанные в порядке убывания приоритета. + +1. Аргументы командной строки 1. +2. Переменные окружения 2. +3. Пользовательский конфигурационный JSON файл 3. +4. Системный конфигурационный JSON файл 3. + +Системный конфигурационный файл имеет наименьший приоритет. \ +Его настройки переопределяются пользовательским конфигурационным файлом, переменными окружения и аргументами командной строки. + +Пользовательский конфигурационный файл имеет приоритет над системным +конфигурационным файлом. \ +Его настройки переопределяются переменными +окружения и аргументами командной строки. + +Переменные окружения имеют приоритет над системным и пользовательским конфигурационными файлами, но уступают аргументам командной строки. + +Аргументы командной строки имеют наивысший приоритет и переопределяют любые настройки, определенные предыдущими способами. + +Если источника конфигурации с меньшим приоритетом не существует, библиотека игнорирует его и переходит к следующему источнику конфигурации. + +Библиотека требует настройки всех обязательных параметров. Без этого будет генерироваться исключение `IncompleteConfigError`.\ +Чтобы исключение не возникало, пользователь должен явно настроить все параметры любым [способом](#configuration_methods). + +> 1 Описание аргументов командной строки приведены в разделе [ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ](#options). \ +2 Описание переменнных окружения приведены в разделе [ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ](#env_variables). \ +3 Шаблон конфигурационного файла с описанием приведен [здесь](#config). + +## ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ +```bash +-sh +--spla-help +``` +Выводит список всех доступных флагов spla с кратким описанием. + +```bash +-sv +--spla-version +``` +Показывает номер версии spla. + +```bash +-ss <путь> +--spla-sconf <путь> +``` +Путь к системному конфигурационному файлу. + +По умолчанию ищет файл в стандартном для данной ОС месте.\ +`/etc/spla/` на Linux. \ +`/Library/Preferences/spla/` на macOS. \ +`%ProgramData%\spla\` на Windows. \ +По умолчанию выбирается первый json файл в соответствующей директории. + +```bash +-su <путь> +--spla-uconf <путь> +``` +Путь к пользовательскому конфигурационному файлу. + +По умолчанию ищет файл в стандартном для данной ОС месте. \ +`~/.config/spla/` на Linux. \ +`~/Library/Application Support/spla/` на macOS. \ +`%APPDATA%\spla\` на Windows. \ +По умолчанию выбирается первый json файл в соответствующей директории. + +```bash +-sp <индекс> +--spla-platform <индекс> +``` +Индекс OpenCL платформы. + +```bash +-sd <индекс> +--spla-device <индекс> +``` +Индекс OpenCL-устройства выбранной платформы (GPU/CPU). + +```bash +-sq <число> +--spla-queues <число> +``` +Количество очередей команд. + +Увеличение числа очередей может повысить производительность +за счет параллельного выполнения независимых задач, но слишком большое значение может снизить производительность из-за накладных расходов. \ +Рекомендуется начинать с 1 и экспериментально подбирать оптимальное значение. + +```bash +-sV <уровень> +--spla-verbosity <уровень> +``` +Уровень детализации отладочной информации, выводимой библиотекой. + +| Уровень | Значение | Описание | +|:-------:|:---------|:---------| +| **0** | OFF | Вывод отключён. Сообщения не выводятся. | +| **1** | ERROR | Только критические ошибки. | +| **2** | WARNING | Ошибки и предупреждения. | +| **3** | INFO | Основные этапы работы библиотеки. | + +Что выводится на каждом уровне: + +1. ERROR — `Error`, `NoAcceleration`, `PlatformNotFound`, `DeviceNotFound`, `InvalidState`, `InvalidArgument`, `CompilationError` + +2. WARNING — добавляет к ERROR: `NoValue`, `NotImplemented` + +3. INFO — добавляет к WARNING: `Ok` - информация об инициализации, выборе платформы/устройства, загрузке конфигурации + +```bash +-sp +--spla-profiling +``` +Профилирование очередей команд OpenCL. + +Bключение профилирования добавляет накладные расходы на каждую +операцию и может замедлить выполнение. + +```bash +-sa <тип> +--spla-allocator <тип> +``` +Тип аллокатора памяти для OpenCL-устройства. \ +Ожидает: lineral | general. + +Выбор аллокатора влияет на производительность операций с памятью. +Линейный аллокатор даёт прирост скорости за счёт последовательного выделения, +но может привести к фрагментации памяти при длительной работе. +Общий аллокатор более надёжен, но медленнее. + +```bash +-sS <размер> +--spla-allocator-size <размер> +``` +Размер линейного аллокатора в байтах. + +Увеличение размера позволяет выделять больше памяти за один раз, но увеличивает потребление ресурсов. \ +Этот параметр необходим только при использовании линейного аллокатора `--spla-allocator linear`. +При использовании общего аллокатора можно не указывать. + +Пример: +```bash +./my_program --spla-uconf ~/my_configs/spla.toml --spla-platform 1 -sd 0 --spla-verbosity 3 -sp true --spla-allocator linear --spla-allocator-size 1048576 +``` + +## ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ +Для всех параметров командной строки (кроме --spla-help, --spla-version) существуют аналоги в виде переменных окружения. + +`SPLA_SYSTEM_CONFIG_PATH` \ +Путь к системному конфигурационному файлу. Аналог параметра --spla-sconf. + +`SPLA_USER_CONFIG_PATH` \ +Путь к пользовательскому конфигурационному файлу. Аналог параметра --spla-uconf. + +`SPLA_OPENCL_PLATFORM` \ +Индекс OpenCL платформы. Аналог параметра --spla-platform. + +`SPLA_OPENCL_DEVICE`\ +Индекс OpenCL-устройства на выбранной платформе. +Аналог параметра --spla-device. + +`SPLA_QUEUES`\ +Количество очередей команд OpenCL. +Аналог параметра --spla-queues. + +`SPLA_VERBOSITY`\ +Уровень детализации отладочной информации. +Аналог параметра --spla-verbosity.\ +Принимает значения от 0 до 3. + +`SPLA_PROFILING`\ +Включает профилирование очередей команд OpenCL. +Аналог параметра --spla-profiling. + +`SPLA_ALLOCATOR`\ +Тип аллокатора памяти для OpenCL-устройства. +Аналог параметра --spla-allocator.\ +Принимает значения: linear, general. + +`SPLA_ALLOCATOR_SIZE`\ +Размер линейного аллокатора в байтах. +Аналог параметра --spla-allocator-size.\ +Имеет смысл только при использовании линейного аллокатора. + + +## КОНФИГУРАЦИОННЫЕ ФАЙЛЫ +Для всех аргументов командной строки (кроме --spla-help, --spla-version, --spla-sconf, --spla-uconf) и всех переменных окружения существуют аналоги в виде параметров конфигурационного файла. + +Формат файла - JSON. + +Типы значений. +1. platform = int +2. device = int +3. queues = int +4. verbosity = int +5. profiling = true | false +6. allocator = linear | general +7. allocator_size = int + +Примеры конфигурационных файлов.\ +Этот формат справедлив как для пользовательского, так и для системного конфигурационного json файла. + +```json +{ + "platform": 1, + "device": 0, + "queues": 4, + "verbosity": 2, + "profiling": false, + "allocator": "linear", + "allocator_size": 1048576 +} +``` \ No newline at end of file From 3e8744399a83f9291f5436f3acb18ede8f336faf Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 8 Sep 2026 03:21:51 +0300 Subject: [PATCH 28/57] unnecessary changes --- src/opencl/Compare.md | 372 ---------------------------------------- src/opencl/UserGuide.md | 13 +- 2 files changed, 7 insertions(+), 378 deletions(-) delete mode 100644 src/opencl/Compare.md diff --git a/src/opencl/Compare.md b/src/opencl/Compare.md deleted file mode 100644 index 6df361e57..000000000 --- a/src/opencl/Compare.md +++ /dev/null @@ -1,372 +0,0 @@ -# Сравнение библиотек для создания механизма конфигурирования -Вся информация взята из репозиториев соответствующих проектов. Дата обращения: 21.04.26. - -## Критерии сравнения - -| Критерий | Метрика | Единицы измерения | -|:---|:---|:---| -| **Зависимости** | наличие | +/- | -| **Источники** | CLI (argv) / env / файлы | +/-, форматы | -| **Стандарт C++** | минимальная версия | C++хх | -| **Поддерживает стандарт иерархии** | Linux/Windows/MacOS | +/- | -| **Способ распространения** | header-only / статическая / динамическая | — | -| **ОС** | Linux / Windows / macOS | +/-, компиляторы | -| **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | -| **Issues** | open, closed/open | n, коэффициент | -| **Сообщество** | GitHub Stars | n | -| **Проходит ли CI** | CI | +/- | - -> ? - не указано в README. - - -## Сравнение парсеров командной строки (CLI) - -| Критерий | CLI11 | cxxopts | -|:---|:---:|:---:| -| Зависимости | - | - | -| **Источники** | | | -|  CLI (argv) | + | + | -|  env | + | - | -|  Файлы | - | - | -| Стандарт C++ | ≥ C++11 | ≥ C++11 | -| **Поддерживает стандарт иерархии** | | | -|  Linux | + | + | -|  Windows | + | + | -|  MacOS | + | + | -| Способ распространения | header-only | header-only -| **ОС** | | | -|  Linux | + (GCC 4.8+, Clang 3.5+) | + (GCC ≥ 4.9, Clang ≥ 3.1) | -|  Windows | + (MSVC ≥ 2015) | + (MSVC ≥ 2015) | -|  macOS | + (AppleClang 7+) | + (Clang ≥ 3.1 с libc++) | -| **Сообщество** | | | -|  Активность (коммитов/мес) | 4 | 1 | -|  Issues всего | 506 | 307 | -|  Issues closed/open | 9 | 6 | -|  Stars | 4.3k | 4.7k | -| Проходит ли CI | + | + | + | - - -## Парсеры файлов - -| Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | config-cxx | taocpp/config -|:---|:---:|:---:|:---:|:---:|:---:|:---:| -| Зависимости | - | - | - | - | - | - | -| **Источники** | -|  CLI (argv) | - | - | - | - | - | - | -|  env | - | - | - | - | + | + | -|  Файлы | JSON | YAML | TOML | TOML | JSON, YAML, XML | JSON, JAXN | -| Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 | ≥ C++20 | ≥ C++17 | -| **Поддерживает стандарт иерархии** | -|  Linux | + | + | + | + | + | + | -|  Windows | + | + | + | + | + | + | -|  MacOS | + | + | + | + | + | + | -| Способ распространения | header-only | статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only | header-only | -| **ОС** | | | -|  Linux | + (GCC 4.8–14.2, Clang 3.4–21.0) | + (GCC, Clang) | + (Clang 8+, GCC 8+) | + (GCC, Clang) | + (GCC 13+, Clang 16+) | + -|  Windows | + (MSVC 2015–2022) | + (MSVC) | + (MSVC VS2019+) | + (MSVC, MinGW) | + (MSVC 143+ (VS 2022)) | + -|  macOS | + (AppleClang 9.1–16.0) | + (Xcode, AppleClang) | + (AppleClang) | + (AppleClang) | + (AppleClang 16+) | + -| **Сообщество** | | | -|  Активность (коммитов/мес) | 2 | 9 | 2 | 4 | 2 | 13 | -|  Issues всего | 3271 | 905 | 193 | 194 | 24 | 5 | -|  Issues closed/open | 68 | 3 | 8 | 5 | 0 open | 0 open | -|  Stars | 49.4k | 15k | 2k | 1.3k | 31 | 194 | -| Проходит ли CI | + | + | + | - | + | ? | - -> ¹ Опционально. - -## Сравнение универсальных инструментов - -| Критерий | Boost.Program_options -|:---|:---:| -| Зависимости | +¹ | -| **Источники** | | | -|  CLI (argv) | + | + | -|  env | + | + | -|  Файлы | INI | -| Стандарт C++ | ≥ C++3 | -| **Поддерживает стандарт иерархии** | | | -|  Linux | + | -|  Windows | + | -|  MacOS | + | -| Способ распространения | статическая/динамическая² | -| **ОС** | | | -|  Linux | + (GCC 5+, Clang 3.6+) | -|  Windows | + (MSVC 2015 (vc140)+) | -|  macOS | + (AppleClang) | -| **Сообщество** | | | -|  Активность (коммитов/мес) | 12 | -|  Issues всего | 400 | -|  Issues closed/open | 1 | -|  Stars | 9.4k | -| Проходит ли CI | + | + | - -> ¹ Список зависимостей: -> 1. Boost.Any -> 2. Boost.Bind -> 3. Boost.Config -> 4. Boost.Core -> 5. Boost.Detail -> 6. Boost.Function -> 7. Boost.Iterator -> 8. Boost.Lexical Cast -> 9. Boost.Smart Ptr -> 10. Boost.ThrowException -> 11. Boost.Tokenizer -> 12. Boost.Type Traits - -> ² Опционально. - - -## Итог: -По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. - - -# Механизм конфигурирования библиотеки SPLA - -## МАНУАЛ: - -## НАЗВАНИЕ -spla - это фреймворк для математических вычислений с использованием GPU/ускорения - -## СИНОПСИС - -```cpp -#include - - -int main(int argc, char* argv[]) { - - spla_configure(argc, argv); - - return 0; -} -``` -Функция `spla_configure(argc, argv)` необходима для обработки аргументов командной строки, переменных окружения и конфигурационных файлов. - -(будет написана) - -## ОПИСАНИЕ -**spla** - это библиотека с открытым исходным кодом, предоставляющая примитивы разреженной линейной алгебры (матрицы, векторы, скаляры) для математических вычислений с ускорением на GPU. Библиотека поддерживает широкий спектр операций, включая умножение матрицы на вектор, решение систем линейных уравнений и другие алгоритмы разреженной алгебры. - -Для большинства пользователей важно, на каком ускорителе будет запускаться их проект, поэтому необходима возможность явного указания графического ускорителя, OpenCL платформы, количества очередей команд и других параметров, влияющих на производительность и удобство пользователя. - -Библиотека предоставляет механизмы конфигурирования, показанные в порядке убывания приоритета. - -1. Аргументы командной строки 1. -2. Переменные окружения 2. -3. Пользовательский конфигурационный TOML/INI файл 3. -4. Системный конфигурационный TOML/INI файл 3. - -Системный конфигурационный файл имеет наименьший приоритет. \ -Его настройки переопределяются пользовательским конфигурационным файлом, переменными окружения и аргументами командной строки. - -Пользовательский конфигурационный файл имеет приоритет над системным -конфигурационным файлом. \ -Его настройки переопределяются переменными -окружения и аргументами командной строки. - -Переменные окружения имеют приоритет над системным и пользовательским конфигурационными файлами, но уступают аргументам командной строки. - -Аргументы командной строки имеют наивысший приоритет и переопределяют любые настройки, определенные предыдущими способами. - -Если источника конфигурации с меньшим приоритетом не существует, библиотека игнорирует его и переходит к следующему источнику конфигурации. - -Библиотека требует настройки всех обязательных параметров. Без этого будет генерироваться исключение `IncompleteConfigError`.\ -Чтобы исключение не возникало, пользователь должен явно настроить все параметры любым [способом](#configuration_methods). - -> 1 Описание аргументов командной строки приведены в разделе [ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ](#options). \ -2 Описание переменнных окружения приведены в разделе [ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ](#env_variables). \ -3 Шаблон конфигурационного файла с описанием приведен [здесь](#config). - -## ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ -```bash --sh ---spla-help -``` -Выводит список всех доступных флагов spla с кратким описанием. - -```bash --sv ---spla-version -``` -Показывает номер версии spla. - -```bash --ss <путь> ---spla-sconf <путь> -``` -Путь к системному конфигурационному файлу. - -По умолчанию ищет файл в стандартном для данной ОС месте.\ -`/etc/spla/spla.toml` на Linux. \ -`/Library/Preferences/spla/spla.toml` на macOS. \ -`%ProgramData%\spla\spla.toml` на Windows. - -```bash --su <путь> ---spla-uconf <путь> -``` -Путь к пользовательскому конфигурационному файлу. - -По умолчанию ищет файл в стандартном для данной ОС месте. \ -`~/.config/spla/spla.toml` на Linux. \ -`~/Library/Application Support/spla/spla.toml` на macOS. \ -`%APPDATA%\spla\spla.toml` на Windows. - -```bash --sp <индекс> ---spla-platform <индекс> -``` -Индекс OpenCL платформы. - -```bash --sd <индекс> ---spla-device <индекс> -``` -Индекс OpenCL-устройства выбранной платформы (GPU/CPU). - -```bash --sq <число> ---spla-queues <число> -``` -Количество очередей команд. - -Увеличение числа очередей может повысить производительность -за счет параллельного выполнения независимых задач, но слишком большое значение может снизить производительность из-за накладных расходов. \ -Рекомендуется начинать с 1 и экспериментально подбирать оптимальное значение. - -```bash --sV <уровень> ---spla-verbosity <уровень> -``` -Уровень детализации отладочной информации, выводимой библиотекой. - -| Уровень | Значение | Описание | -|:-------:|:---------|:---------| -| **0** | OFF | Вывод отключён. Сообщения не выводятся. | -| **1** | ERROR | Только критические ошибки. | -| **2** | WARNING | Ошибки и предупреждения. | -| **3** | INFO | Основные этапы работы библиотеки. | - -Что выводится на каждом уровне: - -1. ERROR — `Error`, `NoAcceleration`, `PlatformNotFound`, `DeviceNotFound`, `InvalidState`, `InvalidArgument`, `CompilationError` - -2. WARNING — добавляет к ERROR: `NoValue`, `NotImplemented` - -3. INFO — добавляет к WARNING: `Ok` - информация об инициализации, выборе платформы/устройства, загрузке конфигурации - -```bash --sp ---spla-profiling -``` -Профилирование очередей команд OpenCL. - -Bключение профилирования добавляет накладные расходы на каждую -операцию и может замедлить выполнение. - -```bash --sa <тип> ---spla-allocator <тип> -``` -Тип аллокатора памяти для OpenCL-устройства. \ -Ожидает: lineral | general. - -Выбор аллокатора влияет на производительность операций с памятью. -Линейный аллокатор даёт прирост скорости за счёт последовательного выделения, -но может привести к фрагментации памяти при длительной работе. -Общий аллокатор более надёжен, но медленнее. - -```bash --sS <размер> ---spla-allocator-size <размер> -``` -Размер линейного аллокатора в байтах. - -Увеличение размера позволяет выделять больше памяти за один раз, но увеличивает потребление ресурсов. \ -Этот параметр необходим только при использовании линейного аллокатора `--spla-allocator linear`. -При использовании общего аллокатора можно не указывать. - -Пример: -```bash -./my_program --spla-uconf ~/my_configs/spla.toml --spla-platform 1 -sd 0 --spla-verbosity 3 -sp true --spla-allocator linear --spla-allocator-size 1048576 -``` - -## ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ -Для всех параметров командной строки (кроме --spla-help, --spla-version) существуют аналоги в виде переменных окружения. - -`SPLA_SYSTEM_CONFIG_PATH` \ -Путь к системному конфигурационному файлу. Аналог параметра --spla-sconf. - -`SPLA_USER_CONFIG_PATH` \ -Путь к пользовательскому конфигурационному файлу. Аналог параметра --spla-uconf. - -`SPLA_OPENCL_PLATFORM` \ -Индекс OpenCL платформы. Аналог параметра --spla-platform. - -`SPLA_OPENCL_DEVICE`\ -Индекс OpenCL-устройства на выбранной платформе. -Аналог параметра --spla-device. - -`SPLA_QUEUES`\ -Количество очередей команд OpenCL. -Аналог параметра --spla-queues. - -`SPLA_VERBOSITY`\ -Уровень детализации отладочной информации. -Аналог параметра --spla-verbosity.\ -Принимает значения от 0 до 3. - -`SPLA_PROFILING`\ -Включает профилирование очередей команд OpenCL. -Аналог параметра --spla-profiling. - -`SPLA_ALLOCATOR`\ -Тип аллокатора памяти для OpenCL-устройства. -Аналог параметра --spla-allocator.\ -Принимает значения: linear, general. - -`SPLA_ALLOCATOR_SIZE`\ -Размер линейного аллокатора в байтах. -Аналог параметра --spla-allocator-size.\ -Имеет смысл только при использовании линейного аллокатора. - - -## КОНФИГУРАЦИОННЫЕ ФАЙЛЫ -Для всех аргументов командной строки (кроме --spla-help, --spla-version, --spla-sconf, --spla-uconf) и всех переменных окружения существуют аналоги в виде параметров конфигурационного файла. - -Формат файла - TOML или INI. - -Типы значений. -1. platform = int -2. device = int -3. queues = int -4. verbosity = int -5. profiling = true | false -6. allocator = linear | general -7. allocator_size = int - -Примеры конфигурационных файлов.\ -Этот формат справедлив как для пользовательского, так и для системного конфигурационного файла. - -Формат TOML. -```toml -platform = 1 -device = 0 -queues = 4 -verbosity = 2 -profiling = false -allocator = "linear" -allocator_size = 1048576 -``` - -Формата INI. -```ini -platform = 1 -device = 0 -queues = 4 -verbosity = 2 -profiling = true -allocator = linear -allocator_size = 1048576 -``` \ No newline at end of file diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 0cdf0428a..6b27d299c 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -17,7 +17,7 @@ ### Решение -Используйте следующую конфигурацию прямо в коде. Скорее всего эти параметры вам подойдут. +Используйте следующую конфигурацию в коде. Скорее всего эти параметры вам подойдут. ```cpp #include @@ -27,8 +27,9 @@ int main(int argc, char* argv[]) { cfg.platform = 0; cfg.device = 0; cfg.queues = 1; - cfg.verbosity = 1; + cfg.prifiling = false; cfg.allocator = "general"; + cfg.verbosity = 1; init(); @@ -49,7 +50,7 @@ int main(int argc, char* argv[]) { export SPLA_PLATFORM=0 export SPLA_DEVICE=0 export SPLA_QUEUES=1 -export SPLA_PROFILING=true +export SPLA_PROFILING=false export SPLA_ALLOCATOR=general export SPLA_VERBOSITY=1 ``` @@ -76,7 +77,7 @@ export SPLA_VERBOSITY=1 export SPLA_PLATFORM=0 export SPLA_DEVICE=0 export SPLA_QUEUES=2 -export SPLA_PROFILING=true +export SPLA_PROFILING=false export SPLA_ALLOCATOR=general export SPLA_VERBOSITY=1 ``` @@ -90,7 +91,7 @@ export SPLA_VERBOSITY=1 "platform": 0, "device": 0, "queues": 2, - "profiling": true, + "profiling": false, "allocator": "general", "verbosity": 1 } @@ -100,7 +101,7 @@ export SPLA_VERBOSITY=1 ## Сравнение производительности на различных устройствах -Вы хотите выбрать лучшее устройство для вашей задачи, сравнить производительность CPU vs GPU, разных GPU, разных аллокаторов. +Вы хотите выбрать лучшее устройство для вашей задачи, сравнить производительность CPU, GPU, разных GPU, разных аллокаторов. ### РЕШЕНИЕ From aa11385994ee61931f8a3fdef5522ca27f7855e1 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 21 Sep 2026 00:49:10 +0300 Subject: [PATCH 29/57] fixed --- src/opencl/cl_accelerator.cpp | 135 ++++++++++++++--- src/opencl/cl_accelerator.hpp | 16 +- src/opencl/cl_configure.cpp | 278 ++++++++++++++-------------------- src/opencl/cl_configure.hpp | 26 ++-- 4 files changed, 254 insertions(+), 201 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index b36a7b96a..948ba49a2 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -39,13 +40,45 @@ namespace spla { CLAccelerator::CLAccelerator() = default; CLAccelerator::~CLAccelerator() = default; + Status CLAccelerator::init_with_configure(int argc, char** argv) { + ConfigStatus status = configure(argc, argv); + if (status == ConfigStatus::HelpRequested || + status == ConfigStatus::VersionRequested) { + return Status::Ok; + } + if (status != ConfigStatus::Ok) return Status::Error; + + auto* acc = get_acc_cl(); + if (!acc) return Status::Error; + return acc->init(); + } + + Status CLAccelerator::init() { m_description = "no platform or device"; - const char* spla_opencl_platform = std::getenv(SPLA_OPENCL_PLATFORM); - const char* spla_opencl_device = std::getenv(SPLA_OPENCL_DEVICE); - int platform_index = (spla_opencl_platform ? std::atoi(spla_opencl_platform) : 0); - int device_index = (spla_opencl_device ? std::atoi(spla_opencl_device) : 0); + Config cfg; + cfg = get_config(); + + int platform_index = cfg.platform.value(); + int device_index = cfg.device.value(); + int queues_count = cfg.queues.value(); + bool profiling = cfg.profiling.value(); + std::string allocator_type = cfg.allocator.value(); + size_t lin_allocator_size = 0; + if (allocator_type == "linear") { + lin_allocator_size = cfg.allocator_size.value_or(0); + } + int verbosity = cfg.verbosity.value(); + + std::cout << "Configuration parametrs:" << std::endl; + std::cout << "OpenCL platform index: " << platform_index << std::endl; + std::cout << "OpenCL device index: " << device_index << std::endl; + std::cout << "Queues number: " << queues_count << std::endl; + std::cout << "Profiling: " << profiling << std::endl; + std::cout << "Allocator: " << allocator_type << std::endl; + if (allocator_type == "linear") std::cout << "Linear allocator size: " << cfg.allocator_size.value() << std::endl; + std::cout << "Verbosity: " << verbosity << std::endl; if (set_platform(platform_index) != Status::Ok) return Status::PlatformNotFound; @@ -53,9 +86,20 @@ namespace spla { if (set_device(device_index) != Status::Ok) return Status::DeviceNotFound; - if (set_queues_count(1) != Status::Ok) + if (set_profiling(profiling) != Status::Ok) return Status::Error; + if (set_queues_count(queues_count) != Status::Ok) + return Status::Error; + + if (allocator_type == "linear") { + if (set_linear_allocator(cfg.allocator_size.value()) != Status::Ok) + return Status::Error; + } else { + if (set_general_allocator() != Status::Ok) + return Status::Error; + } + m_cache = std::make_unique(); // Output handy info @@ -63,16 +107,24 @@ namespace spla { return Status::Ok; } + + Status CLAccelerator::set_platform(int index) { std::vector available_platforms; cl::Platform::get(&available_platforms); if (available_platforms.empty()) { - LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration, check your system runtime"); + LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration"); return Status::PlatformNotFound; } - if (available_platforms.size() <= index) { - LOG_MSG(Status::InvalidArgument, "index out of list of available platforms"); + + if (index < 0) { + LOG_MSG(Status::InvalidArgument, "platform index must be >= 0 (got " << index << ")"); + return Status::InvalidArgument; + } + + if (available_platforms.size() <= static_cast(index)) { + LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_platforms.size() - 1 << ")"); return Status::InvalidArgument; } @@ -81,22 +133,32 @@ namespace spla { m_alloc_linear.reset(); m_alloc_tmp = nullptr; m_device = cl::Device(); - m_platform = available_platforms[index]; + m_profiling_enabled = false; + + m_platform = available_platforms[index]; LOG_MSG(Status::Ok, "select OpenCL platform " << m_platform.getInfo()); return Status::Ok; } + + Status CLAccelerator::set_device(int index) { std::vector available_devices; m_platform.getDevices(CL_DEVICE_TYPE_GPU, &available_devices); if (available_devices.empty()) { - LOG_MSG(Status::DeviceNotFound, "no device in selected platform, check your OpenCL runtime"); + LOG_MSG(Status::DeviceNotFound, "no device to select for OpenCL acceleration"); return Status::DeviceNotFound; } - if (available_devices.size() <= index) { - LOG_MSG(Status::DeviceNotFound, "index out of list of available devices"); - return Status::DeviceNotFound; + + if (index < 0) { + LOG_MSG(Status::InvalidArgument, "device index must be >= 0 (got " << index << ")"); + return Status::InvalidArgument; + } + + if (available_devices.size() <= static_cast(index)) { + LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_devices.size() - 1 << ")"); + return Status::InvalidArgument; } m_device = available_devices[index]; @@ -163,7 +225,6 @@ namespace spla { m_wave_size = 8; } - std::stringstream desc; desc << "OpenCL Acc " << m_platform.getInfo() << " device: " << m_device.getInfo() @@ -175,19 +236,31 @@ namespace spla { m_description = desc.str(); LOG_MSG(Status::Ok, m_description); + return Status::Ok; + } + Status CLAccelerator::set_profiling(bool enabled) { + m_profiling_enabled = enabled; + LOG_MSG(Status::Ok, "set profiling " << (enabled ? "enabled" : "disabled")); return Status::Ok; } + + Status CLAccelerator::set_queues_count(int count) { + if (count <= 0) { + LOG_MSG(Status::InvalidArgument, "queues count must be > 0 (got " << count << ")"); + return Status::InvalidArgument; + } + m_context = cl::Context(m_device); m_queues.clear(); m_queues.reserve(count); for (int i = 0; i < count; i++) { cl_command_queue_properties properties = 0; -#ifndef SPLA_RELEASE - properties = CL_QUEUE_PROFILING_ENABLE; -#endif + if (m_profiling_enabled) { + properties |= CL_QUEUE_PROFILING_ENABLE; + } cl::CommandQueue queue(m_context, properties); m_queues.emplace_back(std::move(queue)); } @@ -196,14 +269,34 @@ namespace spla { m_alloc_general = std::make_unique(); m_alloc_tmp = m_alloc_general.get(); - if (!is_nvidia()) { - m_alloc_linear = std::make_unique(CLAllocLinear::DEFAULT_SIZE, m_addr_align); - m_alloc_tmp = m_alloc_linear.get(); + LOG_MSG(Status::Ok, "configure " << count << " queues for computations" + << " (profiling: " << (m_profiling_enabled ? "ON" : "OFF") << ")"); + return Status::Ok; + } + + + Status CLAccelerator::set_linear_allocator(size_t size) { + if (size == 0) { + LOG_MSG(Status::InvalidArgument, "allocator_size must be > 0 for linear allocator (got " << size << ")"); + return Status::InvalidArgument; } + m_alloc_linear = std::make_unique(size, m_addr_align); + m_alloc_tmp = m_alloc_linear.get(); + LOG_MSG(Status::Ok, "set linear allocator (size: " << size << " bytes)"); + return Status::Ok; + } + - LOG_MSG(Status::Ok, "configure " << count << " queues for computations"); + Status CLAccelerator::set_general_allocator() { + if (!m_alloc_general) { + LOG_MSG(Status::Error, "general allocator not initialized"); + return Status::Error; + } + m_alloc_tmp = m_alloc_general.get(); + LOG_MSG(Status::Ok, "set general allocator"); return Status::Ok; } + const std::string& CLAccelerator::get_name() { return m_name; } diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index f1f8e761a..84c28f8cb 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -70,10 +70,15 @@ namespace spla { CLAccelerator(); ~CLAccelerator() override; - Status init() override; - Status set_platform(int index) override; - Status set_device(int index) override; - Status set_queues_count(int count) override; + Status init_with_configure(int argc, char** argv); + Status init() override; + Status set_platform(int index) override; + Status set_device(int index) override; + Status set_profiling(bool enabled); + Status set_queues_count(int count) override; + Status set_linear_allocator(size_t size); + Status set_general_allocator(); + const std::string& get_name() override; const std::string& get_description() override; const std::string& get_suffix() override; @@ -106,6 +111,7 @@ namespace spla { cl::Platform m_platform; cl::Device m_device; cl::Context m_context; + ankerl::svector m_queues; std::unique_ptr m_cache; std::unique_ptr m_counter_pool; std::unique_ptr m_alloc_linear; @@ -130,7 +136,7 @@ namespace spla { bool m_is_intel = false; bool m_is_img = false; - ankerl::svector m_queues; + bool m_profiling_enabled = false; }; /** diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 7233e6c3f..936650bc5 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -4,13 +4,13 @@ namespace spla { - Config config_user_and_system; + Config config_default; + Config config_system; + Config config_user; Config config_cli_and_env; Config config_final; void Config::merge(const Config& source) { - if (source.system_config_path.has_value()) system_config_path = source.system_config_path; - if (source.user_config_path.has_value()) user_config_path = source.user_config_path; if (source.platform.has_value()) platform = source.platform; if (source.device.has_value()) device = source.device; if (source.queues.has_value()) queues = source.queues; @@ -24,164 +24,94 @@ namespace spla { *this = Config{}; } - std::string get_home_directory() { -#ifdef _WIN32 - const char* home = std::getenv("USERPROFILE"); - if (home) return std::string(home); - const char* drive = std::getenv("HOMEDRIVE"); - const char* path = std::getenv("HOMEPATH"); - if (drive && path) return std::string(drive) + std::string(path); - return ""; + std::string get_spla_version() { + return "SPLA version: 0.0.0"; + } -#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) - const char* home = std::getenv("HOME"); - if (home) return std::string(home); - struct passwd* pw = getpwuid(getuid()); - if (pw) return std::string(pw->pw_dir); - return ""; + std::string get_default_config_path() { +#ifdef _WIN32 + if (const char* pd = std::getenv("PROGRAMDATA")) { + return std::string(pd) + "\\spla\\spla_conf.json"; + } + return "C:\\ProgramData\\spla\\spla_conf.json"; + +#elif defined(__APPLE__) + return "/usr/local/share/spla/spla_conf.json"; + +#elif defined(__linux__) + return "/usr/share/spla/spla_conf.json"; #else - #error "Unsupported operating system" + #error "spla supports only Windows, macOS and Linux" #endif } + std::string get_default_system_config_path() { #ifdef _WIN32 const char* program_data = std::getenv("PROGRAMDATA"); if (program_data) { - return std::string(program_data) + "\\spla\\"; + return std::string(program_data) + "\\spla\\spla_conf.json"; } - return "C:\\ProgramData\\spla\\"; + return "C:\\ProgramData\\spla\\spla_conf.json"; #elif defined(__APPLE__) - return "/Library/Application Support/spla/"; + return "/Library/Application Support/spla/spla_conf.json"; -#elif defined(__linux__) || defined(__unix__) - return "/etc/spla/"; +#elif defined(__linux__) + return "/etc/spla/spla_conf.json"; #else - #error "Unsupported operating system" + #error "spla supports only Windows, macOS and Linux" #endif } - std::string get_default_user_config_path() { - std::string home = get_home_directory(); - if (home.empty()) { - return ""; - } + std::string get_home_directory() { #ifdef _WIN32 - const char* app_data = std::getenv("APPDATA"); - if (app_data) return std::string(app_data) + "\\spla\\"; - return home + "\\AppData\\Roaming\\spla\\"; + const char* home = std::getenv("USERPROFILE"); + if (home) return std::string(home); -#elif defined(__APPLE__) - return home + "/Library/Application Support/spla/"; + const char* drive = std::getenv("HOMEDRIVE"); + const char* path = std::getenv("HOMEPATH"); + if (drive && path) return std::string(drive) + std::string(path); + throw std::runtime_error("Cannot determine home directory"); -#elif defined(__linux__) || defined(__unix__) - return home + "/.config/spla/"; +#elif defined(__APPLE__) || defined(__linux__) + const char* home = std::getenv("HOME"); + if (home) return std::string(home); + + struct passwd* pw = getpwuid(getuid()); + if (pw) return std::string(pw->pw_dir); + throw std::runtime_error("Cannot determine home directory"); #else - #error "Unsupported operating system" + #error "spla supports only Windows, macOS and Linux" #endif } - std::string find_first_json_file(const std::string& directory) { - if (directory.empty() || !std::filesystem::exists(directory)) { - return ""; - } - - for (const auto& entry : std::filesystem::directory_iterator(directory)) { - if (entry.is_regular_file()) { - std::string path = entry.path().string(); - if (path.size() >= 5 && - path.compare(path.size() - 5, 5, ".json") == 0) { - return path; - } - } - } - return ""; - } - ConfigStatus load_from_file(const std::string& path, Config& cfg) { - try { - std::ifstream file(path); - if (!file.is_open()) { - std::cerr << "Failed to open file: " << path << std::endl; - return ConfigStatus::OpenFileError; - } - - nlohmann::json config_data = nlohmann::json::parse(file); - - if (config_data.contains("platform")) { - cfg.platform = config_data["platform"].get(); - } - if (config_data.contains("device")) { - cfg.device = config_data["device"].get(); - } - if (config_data.contains("queues")) { - cfg.queues = config_data["queues"].get(); - } - if (config_data.contains("profiling")) { - cfg.profiling = config_data["profiling"].get(); - } - if (config_data.contains("allocator")) { - cfg.allocator = config_data["allocator"].get(); - } - if (config_data.contains("allocator_size")) { - cfg.allocator_size = config_data["allocator_size"].get(); - } - if (config_data.contains("verbosity")) { - cfg.verbosity = config_data["verbosity"].get(); - } + std::string get_default_user_config_path() { + std::string home = get_home_directory(); - return ConfigStatus::Ok; +#ifdef _WIN32 + const char* app_data = std::getenv("APPDATA"); + if (app_data) return std::string(app_data) + "\\spla\\spla_conf.json"; + return home + "\\AppData\\Roaming\\spla\\spla_conf.json"; - } catch (const nlohmann::json::exception& e) { - std::cerr << "Failed to parse config files" << std::endl; - std::cerr << "Error parsing JSON file '" << path << "': " << e.what() << std::endl; - return ConfigStatus::UserOrSystemConfParseError; - } - } +#elif defined(__APPLE__) + return home + "/Library/Application Support/spla/spla_conf.json"; - ConfigStatus parse_system_and_user_conf(const Config& cli_env_config, Config& file_config) { - std::string sys_dir = cli_env_config.system_config_path.value_or(get_default_system_config_path()); - std::string user_dir = cli_env_config.user_config_path.value_or(get_default_user_config_path()); - - ConfigStatus status = ConfigStatus::Ok; - - if (sys_dir != "") { - std::string sys_file = find_first_json_file(sys_dir); - if (sys_file != "") { - std::cout << "Loading system config: " << sys_file << std::endl; - status = load_from_file(sys_file, file_config); - if (status == ConfigStatus::UserOrSystemConfParseError) return status; - } else - std::cout << "No system config found in: " << sys_dir << std::endl; - } else - std::cout << "System config directory is not set. Skipping." << std::endl; - - if (user_dir != "") { - std::string user_file = find_first_json_file(user_dir); - if (user_file != "") { - std::cout << "Loading user config: " << user_file << std::endl; - status = load_from_file(user_file, file_config); - if (status == ConfigStatus::UserOrSystemConfParseError) return status; - } else - std::cout << "No user config found in: " << user_dir << std::endl; - } else - std::cout << "User config directory is not set. Skipping." << std::endl; - - if (status == ConfigStatus::OpenFileError) return status; +#elif defined(__linux__) || defined(__unix__) + return home + "/.config/spla/spla_conf.json"; - return ConfigStatus::Ok; +#else + #error "spla supports only Windows, macOS and Linux" +#endif } - std::string get_spla_version() { - return "SPLA version: 0.0.0"; - } ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg) { CLI::App app{"SPLA configuration"}; @@ -189,16 +119,6 @@ namespace spla { app.add_flag("-sh,--spla-help", cfg.help, "Show help and exit"); app.add_flag("-sv,--spla-version", cfg.version, "Show version and exit"); - app.add_option("-ss,--spla-sconf", cfg.system_config_path, - "Path to system configuration file\n" - "Config key: (not used in config file)") - ->envname("SPLA_SYSTEM_CONFIG_PATH"); - - app.add_option("-su,--spla-uconf", cfg.user_config_path, - "Path to user configuration file\n" - "Config key: (not used in config file)") - ->envname("SPLA_USER_CONFIG_PATH"); - app.add_option("-sp,--spla-platform", cfg.platform, "OpenCL platform index\n" "Config key: platform") @@ -260,6 +180,48 @@ namespace spla { } + ConfigStatus parse_file(const std::string& path, Config& cfg) { + try { + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "Failed to open file: " << path << std::endl; + return ConfigStatus::OpenFileError; + } + + nlohmann::json config_data = nlohmann::json::parse(file); + + if (config_data.contains("platform")) { + cfg.platform = config_data["platform"].get(); + } + if (config_data.contains("device")) { + cfg.device = config_data["device"].get(); + } + if (config_data.contains("queues")) { + cfg.queues = config_data["queues"].get(); + } + if (config_data.contains("profiling")) { + cfg.profiling = config_data["profiling"].get(); + } + if (config_data.contains("allocator")) { + cfg.allocator = config_data["allocator"].get(); + } + if (config_data.contains("allocator_size")) { + cfg.allocator_size = config_data["allocator_size"].get(); + } + if (config_data.contains("verbosity")) { + cfg.verbosity = config_data["verbosity"].get(); + } + + return ConfigStatus::Ok; + + } catch (const nlohmann::json::exception& e) { + std::cerr << "Failed to parse config files" << std::endl; + std::cerr << "Error parsing JSON file '" << path << "': " << e.what() << std::endl; + return ConfigStatus::ParseConfError; + } + } + + ConfigStatus check_platform_and_device(int platform_index, int device_index) { if (platform_index < 0) { @@ -280,7 +242,6 @@ namespace spla { return ConfigStatus::PlatformNotFound; } - if (device_index < 0) { std::cerr << "Error: device must be >= 0 (got " << device_index << ")" << std::endl; return ConfigStatus::InvalidConfigParams; @@ -334,7 +295,6 @@ namespace spla { return ConfigStatus::MissedParametrs; } - ConfigStatus status; status = check_platform_and_device(*cfg.platform, *cfg.device); @@ -342,13 +302,11 @@ namespace spla { return status; } - if (*cfg.queues <= 0) { std::cerr << "Error: queues must be > 0 (got " << *cfg.queues << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } - if (*cfg.allocator != "linear" && *cfg.allocator != "general") { std::cerr << "Error: allocator must be 'linear' or 'general' (got '" << *cfg.allocator << "')" << std::endl; return ConfigStatus::InvalidConfigParams; @@ -361,47 +319,43 @@ namespace spla { } } - if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { std::cerr << "Error: verbosity must be between 0 and 3 (got " << *cfg.verbosity << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } - return ConfigStatus::Ok; } ConfigStatus configure(int argc, char** argv) { - config_user_and_system.reset(); + config_default.reset(); + config_system.reset(); + config_user.reset(); config_cli_and_env.reset(); config_final.reset(); - ConfigStatus config_status; + ConfigStatus status; - config_status = parse_cli_and_env(argc, argv, config_cli_and_env); - if (config_status != ConfigStatus::CliOrEnvParseError) return config_status; - else { - std::exit(1); - } + status = parse_cli_and_env(argc, argv, config_cli_and_env); + if (status == ConfigStatus::CliOrEnvParseError) return status; - config_status = parse_system_and_user_conf(config_cli_and_env, config_user_and_system); - if (config_status != ConfigStatus::UserOrSystemConfParseError) return config_status; - else { - std::exit(1); - } + status = parse_file(get_default_user_config_path(), config_user); + if (status == ConfigStatus::ParseConfError) return status; - config_final = config_user_and_system; - config_final.merge(config_cli_and_env); + status = parse_file(get_default_system_config_path(), config_system); + if (status == ConfigStatus::ParseConfError) return status; - auto* acc = get_acc_cl(); - if (!acc) { - std::exit(1); - } + status = parse_file(get_default_config_path(), config_default); + if (status == ConfigStatus::ParseConfError) return status; - Status status = acc->init(); - if (status != Status::Ok) { - std::exit(1); - } + + config_final.merge(config_default); + config_final.merge(config_system); + config_final.merge(config_user); + config_final.merge(config_cli_and_env); + + status = validate(config_final); + if (status != ConfigStatus::Ok) return status; return ConfigStatus::Ok; } diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index d470fbbfe..558016199 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -17,8 +17,6 @@ namespace spla { struct Config { std::optional help; std::optional version; - std::optional system_config_path; - std::optional user_config_path; std::optional platform; std::optional device; std::optional queues; @@ -37,29 +35,31 @@ namespace spla { VersionRequested, CliOrEnvParseError, - UserOrSystemConfParseError, + ParseConfError, OpenFileError, MissedParametrs, PlatformNotFound, DeviceNotFound, - InvalidConfigParams + InvalidConfigParams, + Error }; - extern Config config_user_and_system; + extern Config config_default; + extern Config config_system; + extern Config config_user; extern Config config_cli_and_env; extern Config config_final; - std::string get_home_directory(); - std::string get_default_system_config_path(); - std::string get_default_user_config_path(); - std::string find_first_json_file(const std::string& directory); - ConfigStatus load_from_file(const std::string& path, Config& cfg); + inline Config get_config() { return config_final; } + std::string get_spla_version(); + std::string get_default_config_path(); + std::string get_default_system_config_path(); + std::string get_home_directory(); + std::string get_default_user_config_path(); - ConfigStatus parse_system_and_user_conf(const Config& cli_env_config, Config& file_config); - - std::string get_spla_version(); ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg); + ConfigStatus parse_file(const std::string& path, Config& cfg); ConfigStatus check_platform_and_device(int platform_index, int device_index); ConfigStatus validate(const Config& cfg); From 60ecdff2dfc03f8128276ed877cb56669c7356e4 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 21 Sep 2026 01:12:09 +0300 Subject: [PATCH 30/57] for formatter and ubuntu build --- src/opencl/cl_accelerator.cpp | 18 +++++++++--------- src/opencl/cl_configure.cpp | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 948ba49a2..053d091a2 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -52,7 +52,7 @@ namespace spla { if (!acc) return Status::Error; return acc->init(); } - + Status CLAccelerator::init() { m_description = "no platform or device"; @@ -60,12 +60,12 @@ namespace spla { Config cfg; cfg = get_config(); - int platform_index = cfg.platform.value(); - int device_index = cfg.device.value(); - int queues_count = cfg.queues.value(); - bool profiling = cfg.profiling.value(); - std::string allocator_type = cfg.allocator.value(); - size_t lin_allocator_size = 0; + int platform_index = cfg.platform.value(); + int device_index = cfg.device.value(); + int queues_count = cfg.queues.value(); + bool profiling = cfg.profiling.value(); + std::string allocator_type = cfg.allocator.value(); + size_t lin_allocator_size = 0; if (allocator_type == "linear") { lin_allocator_size = cfg.allocator_size.value_or(0); } @@ -131,8 +131,8 @@ namespace spla { m_counter_pool.reset(); m_alloc_general.reset(); m_alloc_linear.reset(); - m_alloc_tmp = nullptr; - m_device = cl::Device(); + m_alloc_tmp = nullptr; + m_device = cl::Device(); m_profiling_enabled = false; m_platform = available_platforms[index]; diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 936650bc5..6c9c10e79 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -1,6 +1,6 @@ #include "cl_configure.hpp" #include "cl_accelerator.hpp" -#include "opencl.hpp" +#include "CL/opencl.hpp" namespace spla { From 53fb6c4ff49253381e359d368e56c1810991b26e Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 21 Sep 2026 01:30:55 +0300 Subject: [PATCH 31/57] changed make file --- CMakeLists.txt | 20 ++++++++++++++++++++ src/opencl/cl_configure.cpp | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c8cfa4f0..ea3d3c303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,22 @@ endfunction() add_subdirectory(deps/robin_hood) add_subdirectory(deps/svector) +message(STATUS "Add CLI11 as CLI/ENV parser") +include(FetchContent) + +FetchContent_Declare(CLI11 + GIT_REPOSITORY https://github.com/CLIUtils/CLI11.git + GIT_TAG v2.4.2 +) +FetchContent_MakeAvailable(CLI11) + +message(STATUS "Add nlohmann/json as JSON parser") +FetchContent_Declare(nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) +FetchContent_MakeAvailable(nlohmann_json) + if (SPLA_BUILD_OPENCL) if (SPLA_TARGET_MACOSX) message(STATUS "Add standard Apple OpenCL package") @@ -235,6 +251,8 @@ set(SRC_OPENCL) if (SPLA_BUILD_OPENCL) set(SRC_OPENCL + src/opencl/cl_configure.cpp + src/opencl/cl_configure.hpp src/opencl/cl_debug.hpp src/opencl/cl_accelerator.cpp src/opencl/cl_accelerator.hpp @@ -371,6 +389,8 @@ target_compile_definitions(spla PRIVATE SPLA_EXPORTS) target_link_libraries(spla PRIVATE robin_hood) target_link_libraries(spla PRIVATE svector) +target_link_libraries(spla PRIVATE CLI11::CLI11) +target_link_libraries(spla PRIVATE nlohmann_json::nlohmann_json) if (SPLA_BUILD_OPENCL) target_link_libraries(spla PUBLIC OpenCL) diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 6c9c10e79..575d22aaf 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -1,6 +1,6 @@ #include "cl_configure.hpp" -#include "cl_accelerator.hpp" #include "CL/opencl.hpp" +#include "cl_accelerator.hpp" namespace spla { From 5aa6e52b760af3f722e7010a49d92f30b9cd0d95 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 21 Sep 2026 01:39:55 +0300 Subject: [PATCH 32/57] changed deps in make file --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea3d3c303..334095e71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -395,7 +395,7 @@ target_link_libraries(spla PRIVATE nlohmann_json::nlohmann_json) if (SPLA_BUILD_OPENCL) target_link_libraries(spla PUBLIC OpenCL) target_link_libraries(spla PUBLIC OpenCL::HeadersCpp) - target_compile_definitions(spla PUBLIC CL_TARGET_OPENCL_VERSION=120) + target_compile_definitions(spla PUBLIC CL_TARGET_OPENCL_VERSION=300) list(APPEND SPLA_DEFINES SPLA_BUILD_OPENCL) endif () From 54b10b17a09d708479dc4a4df0e549561da6dd00 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 21 Sep 2026 02:39:41 +0300 Subject: [PATCH 33/57] ! grep -qE \[ FAILED \] --- .github/workflows/self-hosted.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/self-hosted.yml b/.github/workflows/self-hosted.yml index b15d036e5..5b6958d31 100644 --- a/.github/workflows/self-hosted.yml +++ b/.github/workflows/self-hosted.yml @@ -90,7 +90,7 @@ jobs: - name: Check for tests results run: | - ! grep -qi "FAILED" ${{ env.test-file }} + ! grep -qE "\[ FAILED \]" ${{ env.test-file }} clean: name: Cleanup workspace diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 6828c3d40..60c9bdd55 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -106,4 +106,4 @@ jobs: - name: Check for tests results run: | - ! grep -qi "FAILED" ${{ env.test-file }} + ! grep -qE "\[ FAILED \]" ${{ env.test-file }} From 24dcab7a30b5aa45229c38e96efc37271b0659d5 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 21 Sep 2026 02:48:10 +0300 Subject: [PATCH 34/57] CL_TARGET_OPENCL_VERSION=300 --- deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt | 2 +- deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt | 2 +- deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt | 2 +- deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt | 2 +- deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt b/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt index f3e8466ee..b7a535f91 100644 --- a/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt +++ b/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt @@ -19,7 +19,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=120 + CL_TARGET_OPENCL_VERSION=300 ) include(CTest) diff --git a/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt b/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt index aa36d168b..5b0bb6d37 100644 --- a/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt +++ b/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt @@ -20,7 +20,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=120 + CL_TARGET_OPENCL_VERSION=300 ) include(CTest) diff --git a/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt b/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt index f58f21e9e..f9120c2bf 100644 --- a/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt +++ b/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=120 + CL_TARGET_OPENCL_VERSION=300 ) include(CTest) diff --git a/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt b/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt index 436fffdb4..221153e79 100644 --- a/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt +++ b/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt @@ -39,7 +39,7 @@ target_compile_options(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=120 + CL_TARGET_OPENCL_VERSION=300 ) include(CTest) diff --git a/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt b/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt index 83a52b70b..1b2021e1f 100644 --- a/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt +++ b/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt @@ -24,7 +24,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=120 + CL_TARGET_OPENCL_VERSION=300 ) include(CTest) From 2291458e8a45c98232e5c3796c4dd0196d6c8723 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 23 Sep 2026 02:55:44 +0300 Subject: [PATCH 35/57] made verbosity --- include/spla/library.hpp | 15 ++ src/core/logger.cpp | 37 ++++- src/core/logger.hpp | 5 +- src/library.cpp | 6 + src/opencl/cl_accelerator.cpp | 218 +++++++++----------------- src/opencl/cl_accelerator.hpp | 7 +- src/opencl/cl_configure.cpp | 282 +++++++++++++++++++++++++--------- src/opencl/cl_configure.hpp | 50 ++++-- 8 files changed, 385 insertions(+), 235 deletions(-) diff --git a/include/spla/library.hpp b/include/spla/library.hpp index a572cb770..88a1c4a08 100644 --- a/include/spla/library.hpp +++ b/include/spla/library.hpp @@ -114,6 +114,21 @@ namespace spla { */ SPLA_API Status set_message_callback(MessageCallback callback); + /** + * @brief Set verbosity level for library logger + * + * Controls which messages are shown: + * 0 - no output + * 1 - errors only + * 2 - errors + warnings + * 3 - all messages (info, warnings, errors) + * + * @param verbosity Verbosity level [0, 3] + * + * @return Function call status + */ + SPLA_API Status set_verbosity(int verbosity); + /** * @brief Sets default library callback to log messages to console * diff --git a/src/core/logger.cpp b/src/core/logger.cpp index 8fab9010d..5530759d9 100644 --- a/src/core/logger.cpp +++ b/src/core/logger.cpp @@ -31,10 +31,38 @@ namespace spla { - void Logger::log_msg(Status status, const std::string& msg, const std::string& file, const std::string& function, int line) { + static int status_to_level(Status status) { + switch (status) { + case Status::Error: + case Status::PlatformNotFound: + case Status::DeviceNotFound: + case Status::InvalidArgument: + case Status::CompilationError: + return 1; + + case Status::NoAcceleration: + case Status::InvalidState: + case Status::NoValue: + case Status::NotImplemented: + return 2; + + case Status::Ok: + default: + return 3; + } + } + + void Logger::log_msg(Status status, const std::string& msg, + const std::string& file, const std::string& function, int line) { + + int level = status_to_level(status); + if (level > m_verbosity) return; + std::lock_guard guard(m_mutex); std::filesystem::path file_path(file); - if (m_callback) m_callback(status, msg, file_path.filename().string(), function, line); + if (m_callback) { + m_callback(status, msg, file_path.filename().string(), function, line); + } } void Logger::set_msg_callback(MessageCallback callback) { @@ -42,4 +70,9 @@ namespace spla { m_callback = std::move(callback); } + void Logger::set_verbosity(int verbosity) { + std::lock_guard guard(m_mutex); + m_verbosity = verbosity; + } + }// namespace spla \ No newline at end of file diff --git a/src/core/logger.hpp b/src/core/logger.hpp index 8afd7a04e..c00259c79 100644 --- a/src/core/logger.hpp +++ b/src/core/logger.hpp @@ -49,10 +49,11 @@ namespace spla { public: void log_msg(Status status, const std::string& msg, const std::string& file, const std::string& function, int line); void set_msg_callback(MessageCallback callback); + void set_verbosity(int verbosity); private: - MessageCallback m_callback; - + MessageCallback m_callback; + int m_verbosity = 3; mutable std::mutex m_mutex; }; diff --git a/src/library.cpp b/src/library.cpp index d0a5494a1..d5acc0c31 100644 --- a/src/library.cpp +++ b/src/library.cpp @@ -143,6 +143,12 @@ namespace spla { return Status::Ok; } + Status Library::set_verbosity(int verbosity) { + m_logger->set_verbosity(verbosity); + LOG_MSG(Status::Ok, "set verbosity: " << verbosity); + return Status::Ok; + } + Status Library::set_default_callback() { auto callback = [](spla::Status status, const std::string& msg, diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 053d091a2..55a5c99a8 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -1,30 +1,3 @@ -/**********************************************************************************/ -/* This file is part of spla project */ -/* https://github.com/SparseLinearAlgebra/spla */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 SparseLinearAlgebra */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - #include "cl_accelerator.hpp" #include @@ -40,70 +13,72 @@ namespace spla { CLAccelerator::CLAccelerator() = default; CLAccelerator::~CLAccelerator() = default; - Status CLAccelerator::init_with_configure(int argc, char** argv) { - ConfigStatus status = configure(argc, argv); - if (status == ConfigStatus::HelpRequested || - status == ConfigStatus::VersionRequested) { - return Status::Ok; + InitResult init_with_configure(int argc, char** argv) { + InitResult result; + result.config_status = configure(argc, argv); + + if (result.config_status == ConfigStatus::HelpRequested || + result.config_status == ConfigStatus::VersionRequested) { + result.status = Status::Ok; + return result; + } + + if (result.config_status != ConfigStatus::Ok) { + result.status = Status::Error; + return result; } - if (status != ConfigStatus::Ok) return Status::Error; auto* acc = get_acc_cl(); - if (!acc) return Status::Error; - return acc->init(); + if (!acc) { + result.status = Status::NoAcceleration; + return result; + } + + result.status = acc->init(); + return result; } Status CLAccelerator::init() { - m_description = "no platform or device"; - - Config cfg; - cfg = get_config(); - - int platform_index = cfg.platform.value(); - int device_index = cfg.device.value(); - int queues_count = cfg.queues.value(); - bool profiling = cfg.profiling.value(); - std::string allocator_type = cfg.allocator.value(); - size_t lin_allocator_size = 0; + int platform_index = config_final.platform.value(); + int device_index = config_final.device.value(); + int queues_count = config_final.queues.value(); + bool profiling = config_final.profiling.value(); + std::string allocator_type = config_final.allocator.value(); + size_t lin_allocator_size; + if (allocator_type == "linear") lin_allocator_size = config_final.allocator_size.value(); + int verbosity = config_final.verbosity.value(); + + Library::get()->set_verbosity(verbosity); + + LOG_MSG(Status::Ok, "Initializing accelerator..."); + + LOG_MSG(Status::Ok, "Configuration parameters:"); + LOG_MSG(Status::Ok, " platform = " << platform_index); + LOG_MSG(Status::Ok, " device = " << device_index); + LOG_MSG(Status::Ok, " queues = " << queues_count); + LOG_MSG(Status::Ok, " profiling = " << (profiling ? "true" : "false")); + LOG_MSG(Status::Ok, " allocator = " << allocator_type); if (allocator_type == "linear") { - lin_allocator_size = cfg.allocator_size.value_or(0); + LOG_MSG(Status::Ok, " alloc_size= " << lin_allocator_size); } - int verbosity = cfg.verbosity.value(); - - std::cout << "Configuration parametrs:" << std::endl; - std::cout << "OpenCL platform index: " << platform_index << std::endl; - std::cout << "OpenCL device index: " << device_index << std::endl; - std::cout << "Queues number: " << queues_count << std::endl; - std::cout << "Profiling: " << profiling << std::endl; - std::cout << "Allocator: " << allocator_type << std::endl; - if (allocator_type == "linear") std::cout << "Linear allocator size: " << cfg.allocator_size.value() << std::endl; - std::cout << "Verbosity: " << verbosity << std::endl; + LOG_MSG(Status::Ok, " verbosity = " << verbosity); - if (set_platform(platform_index) != Status::Ok) - return Status::PlatformNotFound; - - if (set_device(device_index) != Status::Ok) - return Status::DeviceNotFound; - - if (set_profiling(profiling) != Status::Ok) - return Status::Error; - - if (set_queues_count(queues_count) != Status::Ok) - return Status::Error; + set_platform(platform_index); + set_device(device_index); + set_profiling(profiling); + set_queues_count(queues_count); if (allocator_type == "linear") { - if (set_linear_allocator(cfg.allocator_size.value()) != Status::Ok) - return Status::Error; + set_linear_allocator(lin_allocator_size); } else { - if (set_general_allocator() != Status::Ok) - return Status::Error; + set_general_allocator(); } m_cache = std::make_unique(); + LOG_MSG(Status::Ok, "program cache created"); - // Output handy info - LOG_MSG(Status::Ok, "Initialize accelerator: " << get_description()); + LOG_MSG(Status::Ok, "accelerator initialized: " << get_description()); return Status::Ok; } @@ -113,21 +88,6 @@ namespace spla { std::vector available_platforms; cl::Platform::get(&available_platforms); - if (available_platforms.empty()) { - LOG_MSG(Status::PlatformNotFound, "no platform to select for OpenCL acceleration"); - return Status::PlatformNotFound; - } - - if (index < 0) { - LOG_MSG(Status::InvalidArgument, "platform index must be >= 0 (got " << index << ")"); - return Status::InvalidArgument; - } - - if (available_platforms.size() <= static_cast(index)) { - LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_platforms.size() - 1 << ")"); - return Status::InvalidArgument; - } - m_counter_pool.reset(); m_alloc_general.reset(); m_alloc_linear.reset(); @@ -136,7 +96,8 @@ namespace spla { m_profiling_enabled = false; m_platform = available_platforms[index]; - LOG_MSG(Status::Ok, "select OpenCL platform " << m_platform.getInfo()); + LOG_MSG(Status::Ok, "select OpenCL platform: " + << m_platform.getInfo()); return Status::Ok; } @@ -144,25 +105,11 @@ namespace spla { Status CLAccelerator::set_device(int index) { std::vector available_devices; - m_platform.getDevices(CL_DEVICE_TYPE_GPU, &available_devices); - - if (available_devices.empty()) { - LOG_MSG(Status::DeviceNotFound, "no device to select for OpenCL acceleration"); - return Status::DeviceNotFound; - } - - if (index < 0) { - LOG_MSG(Status::InvalidArgument, "device index must be >= 0 (got " << index << ")"); - return Status::InvalidArgument; - } - - if (available_devices.size() <= static_cast(index)) { - LOG_MSG(Status::InvalidArgument, "platform index out of range (got " << index << ", max " << available_devices.size() - 1 << ")"); - return Status::InvalidArgument; - } + m_platform.getDevices(CL_DEVICE_TYPE_ALL, &available_devices); m_device = available_devices[index]; - LOG_MSG(Status::Ok, "select OpenCL device " << m_device.getInfo()); + LOG_MSG(Status::Ok, "select OpenCL device: " + << m_device.getInfo()); m_vendor_code.clear(); m_vendor_name = m_device.getInfo(); @@ -170,7 +117,7 @@ namespace spla { m_max_cu = m_device.getInfo(); m_max_wgs = m_device.getInfo(); m_max_local_mem = m_device.getInfo(); - m_addr_align = m_device.getInfo() / 8;// from bits to bytes + m_addr_align = m_device.getInfo() / 8; m_is_nvidia = false; m_is_amd = false; @@ -206,7 +153,6 @@ namespace spla { m_wave_size = 64; m_is_amd = true; - // Likely, it is an integrated amd device if (m_max_wgs <= 256 || m_max_cu == 1) m_wave_size = 16; } if (m_vendor_name.find("Imagination Technologies") != std::string::npos || @@ -220,38 +166,35 @@ namespace spla { } if (m_vendor_code.empty()) { - LOG_MSG(Status::Error, "failed to match one of the pre-defined vendors"); + LOG_MSG(Status::InvalidArgument, "unknown vendor: " << m_vendor_name + << ", using default parameters"); m_default_wgs = 64; m_wave_size = 8; } std::stringstream desc; - desc << "OpenCL Acc " << m_platform.getInfo() - << " device: " << m_device.getInfo() - << " vendor:" << m_vendor_code - << " mcu:" << m_max_cu - << " wave:" << m_wave_size - << " mwgs:" << m_max_wgs; + desc << "OpenCL " + << m_platform.getInfo() + << " | device: " << m_device.getInfo() + << " | vendor: " << m_vendor_code + << " | mcu: " << m_max_cu + << " | wave: " << m_wave_size + << " | mwgs: " << m_max_wgs; m_description = desc.str(); - LOG_MSG(Status::Ok, m_description); return Status::Ok; } + Status CLAccelerator::set_profiling(bool enabled) { m_profiling_enabled = enabled; - LOG_MSG(Status::Ok, "set profiling " << (enabled ? "enabled" : "disabled")); + LOG_MSG(Status::Ok, "set profiling: " << (enabled ? "enabled" : "disabled")); return Status::Ok; } Status CLAccelerator::set_queues_count(int count) { - if (count <= 0) { - LOG_MSG(Status::InvalidArgument, "queues count must be > 0 (got " << count << ")"); - return Status::InvalidArgument; - } - m_context = cl::Context(m_device); m_queues.clear(); m_queues.reserve(count); @@ -265,21 +208,15 @@ namespace spla { m_queues.emplace_back(std::move(queue)); } - m_counter_pool = std::make_unique(); - m_alloc_general = std::make_unique(); - m_alloc_tmp = m_alloc_general.get(); + m_counter_pool = std::make_unique(); - LOG_MSG(Status::Ok, "configure " << count << " queues for computations" + LOG_MSG(Status::Ok, "configure " << count << " queues" << " (profiling: " << (m_profiling_enabled ? "ON" : "OFF") << ")"); return Status::Ok; } Status CLAccelerator::set_linear_allocator(size_t size) { - if (size == 0) { - LOG_MSG(Status::InvalidArgument, "allocator_size must be > 0 for linear allocator (got " << size << ")"); - return Status::InvalidArgument; - } m_alloc_linear = std::make_unique(size, m_addr_align); m_alloc_tmp = m_alloc_linear.get(); LOG_MSG(Status::Ok, "set linear allocator (size: " << size << " bytes)"); @@ -288,23 +225,14 @@ namespace spla { Status CLAccelerator::set_general_allocator() { - if (!m_alloc_general) { - LOG_MSG(Status::Error, "general allocator not initialized"); - return Status::Error; - } - m_alloc_tmp = m_alloc_general.get(); + m_alloc_general = std::make_unique(); + m_alloc_tmp = m_alloc_general.get(); LOG_MSG(Status::Ok, "set general allocator"); return Status::Ok; } - const std::string& CLAccelerator::get_name() { - return m_name; - } - const std::string& CLAccelerator::get_description() { - return m_description; - } - const std::string& CLAccelerator::get_suffix() { - return m_suffix; - } + const std::string& CLAccelerator::get_name() { return m_name; } + const std::string& CLAccelerator::get_description() { return m_description; } + const std::string& CLAccelerator::get_suffix() { return m_suffix; } }// namespace spla \ No newline at end of file diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 84c28f8cb..1844dbcfe 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -56,6 +56,12 @@ namespace spla { + struct InitResult { + Status status; + ConfigStatus config_status; + }; + InitResult init_with_configure(int argc, char** argv); + /** * @addtogroup internal * @{ @@ -70,7 +76,6 @@ namespace spla { CLAccelerator(); ~CLAccelerator() override; - Status init_with_configure(int argc, char** argv); Status init() override; Status set_platform(int index) override; Status set_device(int index) override; diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 575d22aaf..bfb2a56eb 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -2,6 +2,9 @@ #include "CL/opencl.hpp" #include "cl_accelerator.hpp" +#include +#include + namespace spla { Config config_default; @@ -10,21 +13,46 @@ namespace spla { Config config_cli_and_env; Config config_final; - void Config::merge(const Config& source) { - if (source.platform.has_value()) platform = source.platform; - if (source.device.has_value()) device = source.device; - if (source.queues.has_value()) queues = source.queues; - if (source.profiling.has_value()) profiling = source.profiling; - if (source.allocator.has_value()) allocator = source.allocator; - if (source.allocator_size.has_value()) allocator_size = source.allocator_size; - if (source.verbosity.has_value()) verbosity = source.verbosity; + + void Profile::merge(const Profile& src) { + if (src.platform.has_value()) platform = src.platform; + if (src.device.has_value()) device = src.device; + if (src.queues.has_value()) queues = src.queues; + if (src.profiling.has_value()) profiling = src.profiling; + if (src.allocator.has_value()) allocator = src.allocator; + if (src.allocator_size.has_value()) allocator_size = src.allocator_size; + if (src.verbosity.has_value()) verbosity = src.verbosity; + if (src.extends.has_value()) extends = src.extends; + } + + + void Config::merge(const Config& src) { + if (src.platform.has_value()) platform = src.platform; + if (src.device.has_value()) device = src.device; + if (src.queues.has_value()) queues = src.queues; + if (src.profiling.has_value()) profiling = src.profiling; + if (src.allocator.has_value()) allocator = src.allocator; + if (src.allocator_size.has_value()) allocator_size = src.allocator_size; + if (src.verbosity.has_value()) verbosity = src.verbosity; + + if (src.profile.has_value()) profile = src.profile; + + if (src.profiles.has_value()) { + if (!profiles.has_value()) { + profiles = src.profiles; + } else { + for (const auto& [name, src_prof] : *src.profiles) { + auto& dst_prof = (*profiles)[name]; + dst_prof.merge(src_prof); + } + } + } } void Config::reset() { *this = Config{}; } - std::string get_spla_version() { return "SPLA version: 0.0.0"; } @@ -158,11 +186,16 @@ namespace spla { " 3: All messages (info, warnings, errors)") ->envname("SPLA_VERBOSITY"); + app.add_option("-sP,--spla-profile", cfg.profile, + "Configuration profile name\n" + "Overrides base settings with the named profile.\n" + "Config key: profile") + ->envname("SPLA_PROFILE"); + try { app.parse(argc, argv); } catch (const CLI::ParseError& e) { - std::cerr << "Failed to parse CLI/ENV" << std::endl; - app.exit(e); + std::cerr << "[spla:cli_env] ERROR: failed to parse: " << e.what() << std::endl; return ConfigStatus::CliOrEnvParseError; } @@ -181,42 +214,52 @@ namespace spla { ConfigStatus parse_file(const std::string& path, Config& cfg) { - try { - std::ifstream file(path); - if (!file.is_open()) { - std::cerr << "Failed to open file: " << path << std::endl; - return ConfigStatus::OpenFileError; - } - nlohmann::json config_data = nlohmann::json::parse(file); + if (!std::filesystem::exists(path)) { + std::cerr << "[spla:config] WARNING: file not found: " << path << std::endl; + return ConfigStatus::Ok; + } - if (config_data.contains("platform")) { - cfg.platform = config_data["platform"].get(); - } - if (config_data.contains("device")) { - cfg.device = config_data["device"].get(); - } - if (config_data.contains("queues")) { - cfg.queues = config_data["queues"].get(); - } - if (config_data.contains("profiling")) { - cfg.profiling = config_data["profiling"].get(); - } - if (config_data.contains("allocator")) { - cfg.allocator = config_data["allocator"].get(); - } - if (config_data.contains("allocator_size")) { - cfg.allocator_size = config_data["allocator_size"].get(); - } - if (config_data.contains("verbosity")) { - cfg.verbosity = config_data["verbosity"].get(); + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "[spla:config] WARNING: cannot open: " << path << std::endl; + return ConfigStatus::OpenFileError; + } + + try { + nlohmann::json data = nlohmann::json::parse(file); + + if (data.contains("platform")) cfg.platform = data["platform"].get(); + if (data.contains("device")) cfg.device = data["device"].get(); + if (data.contains("queues")) cfg.queues = data["queues"].get(); + if (data.contains("profiling")) cfg.profiling = data["profiling"].get(); + if (data.contains("allocator")) cfg.allocator = data["allocator"].get(); + if (data.contains("allocator_size")) cfg.allocator_size = data["allocator_size"].get(); + if (data.contains("verbosity")) cfg.verbosity = data["verbosity"].get(); + if (data.contains("profile")) cfg.profile = data["profile"].get(); + + if (data.contains("profiles")) { + std::map profiles; + for (auto& [name, p] : data["profiles"].items()) { + Profile prof; + if (p.contains("platform")) prof.platform = p["platform"].get(); + if (p.contains("device")) prof.device = p["device"].get(); + if (p.contains("queues")) prof.queues = p["queues"].get(); + if (p.contains("profiling")) prof.profiling = p["profiling"].get(); + if (p.contains("allocator")) prof.allocator = p["allocator"].get(); + if (p.contains("allocator_size")) prof.allocator_size = p["allocator_size"].get(); + if (p.contains("verbosity")) prof.verbosity = p["verbosity"].get(); + if (p.contains("extends")) prof.extends = p["extends"].get>(); + profiles[name] = prof; + } + cfg.profiles = profiles; } return ConfigStatus::Ok; } catch (const nlohmann::json::exception& e) { - std::cerr << "Failed to parse config files" << std::endl; - std::cerr << "Error parsing JSON file '" << path << "': " << e.what() << std::endl; + std::cerr << "[spla:config] ERROR: failed to parse '" + << path << "': " << e.what() << std::endl; return ConfigStatus::ParseConfError; } } @@ -225,7 +268,8 @@ namespace spla { ConfigStatus check_platform_and_device(int platform_index, int device_index) { if (platform_index < 0) { - std::cerr << "Error: platform must be >= 0 (got " << platform_index << ")" << std::endl; + std::cerr << "[spla:opencl] ERROR: platform must be >= 0 (got " + << platform_index << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } @@ -233,17 +277,20 @@ namespace spla { cl::Platform::get(&platforms); if (platforms.empty()) { - std::cerr << "Error: no platform to select for OpenCL acceleration" << std::endl; + std::cerr << "[spla:opencl] ERROR: no platform available" << std::endl; return ConfigStatus::PlatformNotFound; } if (static_cast(platform_index) >= platforms.size()) { - std::cerr << "Error: platform index out of range (got " << platform_index << ", max " << platforms.size() - 1 << ")" << std::endl; + std::cerr << "[spla:opencl] ERROR: platform index out of range (got " + << platform_index << ", max " << platforms.size() - 1 << ")" + << std::endl; return ConfigStatus::PlatformNotFound; } if (device_index < 0) { - std::cerr << "Error: device must be >= 0 (got " << device_index << ")" << std::endl; + std::cerr << "[spla:opencl] ERROR: device must be >= 0 (got " + << device_index << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } @@ -251,12 +298,15 @@ namespace spla { platforms[platform_index].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - std::cerr << "Error: no device to select for OpenCL acceleration" << std::endl; + std::cerr << "[spla:opencl] ERROR: no device available on platform " + << platform_index << std::endl; return ConfigStatus::DeviceNotFound; } if (static_cast(device_index) >= devices.size()) { - std::cerr << "Error: device index out of range (got " << device_index << ", max " << devices.size() - 1 << ")" << std::endl; + std::cerr << "[spla:opencl] ERROR: device index out of range (got " + << device_index << ", max " << devices.size() - 1 << ")" + << std::endl; return ConfigStatus::DeviceNotFound; } @@ -264,35 +314,37 @@ namespace spla { } - ConfigStatus validate(const Config& cfg) { + ConfigStatus validation(const Config& cfg) { if (!cfg.platform.has_value()) { - std::cerr << "Error: platform is required" << std::endl; - return ConfigStatus::MissedParametrs; + std::cerr << "[spla:validation] ERROR: required: platform" << std::endl; + return ConfigStatus::MissedParameters; } if (!cfg.device.has_value()) { - std::cerr << "Error: device is required" << std::endl; - return ConfigStatus::MissedParametrs; + std::cerr << "[spla:validation] ERROR: required: device" << std::endl; + return ConfigStatus::MissedParameters; } if (!cfg.queues.has_value()) { - std::cerr << "Error: queues is required" << std::endl; - return ConfigStatus::MissedParametrs; + std::cerr << "[spla:validation] ERROR: required: queues" << std::endl; + return ConfigStatus::MissedParameters; } if (!cfg.profiling.has_value()) { - std::cerr << "Error: profiling is required" << std::endl; - return ConfigStatus::MissedParametrs; + std::cerr << "[spla:validation] ERROR: required: profiling" << std::endl; + return ConfigStatus::MissedParameters; } if (!cfg.allocator.has_value()) { - std::cerr << "Error: allocator is required" << std::endl; - return ConfigStatus::MissedParametrs; - } - if (cfg.allocator.value() == "linear" && !cfg.allocator_size.has_value()) { - std::cerr << "Error: allocator_size is required for linear allocator" << std::endl; - return ConfigStatus::MissedParametrs; + std::cerr << "[spla:validation] ERROR: required: allocator" << std::endl; + return ConfigStatus::MissedParameters; } if (!cfg.verbosity.has_value()) { - std::cerr << "Error: verbosity is required" << std::endl; - return ConfigStatus::MissedParametrs; + std::cerr << "[spla:validation] ERROR: required: verbosity" << std::endl; + return ConfigStatus::MissedParameters; + } + + if (cfg.allocator.value() == "linear" && !cfg.allocator_size.has_value()) { + std::cerr << "[spla:validation] ERROR: allocator_size is required for 'linear' allocator" + << std::endl; + return ConfigStatus::MissedParameters; } ConfigStatus status; @@ -303,26 +355,96 @@ namespace spla { } if (*cfg.queues <= 0) { - std::cerr << "Error: queues must be > 0 (got " << *cfg.queues << ")" << std::endl; + std::cerr << "[spla:validation] ERROR: queues must be > 0 (got " + << *cfg.queues << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } if (*cfg.allocator != "linear" && *cfg.allocator != "general") { - std::cerr << "Error: allocator must be 'linear' or 'general' (got '" << *cfg.allocator << "')" << std::endl; + std::cerr << "[spla:validation] ERROR: allocator must be 'linear' or 'general' (got '" + << *cfg.allocator << "')" << std::endl; return ConfigStatus::InvalidConfigParams; } - if (*cfg.allocator == "linear") { - if (*cfg.allocator_size <= 0) { - std::cerr << "Error: allocator_size must be > 0 for linear allocator (got " << *cfg.allocator_size << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } + if (*cfg.allocator == "linear" && *cfg.allocator_size <= 0) { + std::cerr << "[spla:validation] ERROR: allocator_size must be > 0 for 'linear' (got " + << *cfg.allocator_size << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; } if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { - std::cerr << "Error: verbosity must be between 0 and 3 (got " << *cfg.verbosity << ")" << std::endl; + std::cerr << "[spla:validation] ERROR: verbosity must be in [0, 3] (got " + << *cfg.verbosity << ")" << std::endl; return ConfigStatus::InvalidConfigParams; } + + return ConfigStatus::Ok; + } + + + Profile apply_extends(const std::map& profiles, + const std::string& name, + std::set& stack) { + if (stack.count(name)) { + throw std::runtime_error("Profile cycle detected: " + name); + } + stack.insert(name); + + auto it = profiles.find(name); + if (it == profiles.end()) { + throw std::runtime_error("Profile not found: " + name); + } + + const Profile& prof = it->second; + Profile result; + + if (prof.extends) { + for (const auto& parent_name : *prof.extends) { + Profile parent = apply_extends(profiles, parent_name, stack); + result.merge(parent); + } + } + + result.merge(prof); + + stack.erase(name); + return result; + } + + ConfigStatus apply_profile(Config& cfg) { + + if (!cfg.profile.has_value()) return ConfigStatus::Ok; + + std::string profile_name = *cfg.profile; + + if (!cfg.profiles || !cfg.profiles->count(profile_name)) { + std::cerr << "[spla:profile] ERROR: not found: " << profile_name << std::endl; + return ConfigStatus::ProfileNotFound; + } + + std::set stack; + Profile resolved; + try { + resolved = apply_extends(*cfg.profiles, profile_name, stack); + } catch (const std::runtime_error& e) { + std::string msg = e.what(); + if (msg.find("cycle") != std::string::npos) { + std::cerr << "[spla:profile] ERROR: cycle detected: " + << profile_name << std::endl; + return ConfigStatus::ProfileCycle; + } + std::cerr << "[spla:profile] ERROR: " << msg << std::endl; + return ConfigStatus::ProfileNotFound; + } + + if (resolved.platform) cfg.platform = resolved.platform; + if (resolved.device) cfg.device = resolved.device; + if (resolved.queues) cfg.queues = resolved.queues; + if (resolved.profiling) cfg.profiling = resolved.profiling; + if (resolved.allocator) cfg.allocator = resolved.allocator; + if (resolved.allocator_size) cfg.allocator_size = resolved.allocator_size; + if (resolved.verbosity) cfg.verbosity = resolved.verbosity; + return ConfigStatus::Ok; } @@ -337,26 +459,38 @@ namespace spla { ConfigStatus status; status = parse_cli_and_env(argc, argv, config_cli_and_env); - if (status == ConfigStatus::CliOrEnvParseError) return status; + if (status != ConfigStatus::Ok) return status; status = parse_file(get_default_user_config_path(), config_user); if (status == ConfigStatus::ParseConfError) return status; + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] WARNING: cannot open user config, skipping" << std::endl; + } status = parse_file(get_default_system_config_path(), config_system); if (status == ConfigStatus::ParseConfError) return status; + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] WARNING: cannot open system config, skipping" << std::endl; + } status = parse_file(get_default_config_path(), config_default); if (status == ConfigStatus::ParseConfError) return status; - + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] WARNING: cannot open default config, skipping" << std::endl; + } config_final.merge(config_default); config_final.merge(config_system); config_final.merge(config_user); config_final.merge(config_cli_and_env); - status = validate(config_final); + status = apply_profile(config_final); + if (status != ConfigStatus::Ok) return status; + + status = validation(config_final); if (status != ConfigStatus::Ok) return status; + std::cerr << "[spla:configure]: configuration complete" << std::endl; return ConfigStatus::Ok; } }// namespace spla diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 558016199..0872b62fc 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -1,7 +1,10 @@ #pragma once +#include #include +#include #include +#include #include "CLI/CLI.hpp" #include @@ -14,6 +17,19 @@ namespace spla { + struct Profile { + std::optional platform; + std::optional device; + std::optional queues; + std::optional profiling; + std::optional allocator; + std::optional allocator_size; + std::optional verbosity; + std::optional> extends; + + void merge(const Profile& source); + }; + struct Config { std::optional help; std::optional version; @@ -25,24 +41,31 @@ namespace spla { std::optional allocator_size; std::optional verbosity; + std::optional profile; + std::optional> profiles; + void merge(const Config& source); void reset(); }; + enum ConfigStatus { Ok, + HelpRequested, VersionRequested, - CliOrEnvParseError, + ParseConfError, OpenFileError, - MissedParametrs, + ProfileNotFound, + ProfileCycle, + + MissedParameters, PlatformNotFound, DeviceNotFound, - InvalidConfigParams, - Error + InvalidConfigParams }; extern Config config_default; @@ -51,18 +74,23 @@ namespace spla { extern Config config_cli_and_env; extern Config config_final; - inline Config get_config() { return config_final; } - std::string get_spla_version(); - std::string get_default_config_path(); - std::string get_default_system_config_path(); - std::string get_home_directory(); - std::string get_default_user_config_path(); + std::string get_spla_version(); + + std::string get_default_config_path(); + std::string get_default_system_config_path(); + std::string get_home_directory(); + std::string get_default_user_config_path(); ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg); ConfigStatus parse_file(const std::string& path, Config& cfg); ConfigStatus check_platform_and_device(int platform_index, int device_index); - ConfigStatus validate(const Config& cfg); + ConfigStatus validation(const Config& cfg); + + Profile apply_extends(const std::map& profiles, + const std::string& name, + std::set& stack); + ConfigStatus apply_profile(Config& cfg); ConfigStatus configure(int argc, char** argv); From 30821144c407327112a226e2b3097bdfb80185cf Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 23 Sep 2026 03:00:50 +0300 Subject: [PATCH 36/57] added MIT license back --- src/opencl/cl_accelerator.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 55a5c99a8..ef3f40538 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -1,3 +1,30 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/SparseLinearAlgebra/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + #include "cl_accelerator.hpp" #include From 0b14b378aa3e600f1498e0f0a3bc8d308516c72f Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 23 Sep 2026 03:02:09 +0300 Subject: [PATCH 37/57] add MIT license to cl_configure --- src/opencl/cl_configure.cpp | 27 +++++++++++++++++++++++++++ src/opencl/cl_configure.hpp | 27 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index bfb2a56eb..94ed1e99f 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -1,3 +1,30 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/SparseLinearAlgebra/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + #include "cl_configure.hpp" #include "CL/opencl.hpp" #include "cl_accelerator.hpp" diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 0872b62fc..6ddef1b2c 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -1,3 +1,30 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/SparseLinearAlgebra/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + #pragma once #include From 48613f82ea153e5e18695399c1eee0b86aa0b89e Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Thu, 24 Sep 2026 05:48:19 +0300 Subject: [PATCH 38/57] made new user guide --- src/opencl/UserGuide.md | 284 ++++++++++++++++++++++++++++++---------- 1 file changed, 212 insertions(+), 72 deletions(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 6b27d299c..921dcbefe 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -1,108 +1,248 @@ -## РУКОВОДСТВО ПОЛЬЗОВАТЕЛЯ +# User Guide -Здесь представлены основные сценарии использования spla и рекоммендации по поводу ее использования. +Руководство по установке, проверке и настройке библиотеки spla. +## Содержание -[Первоначальная настройка для нового пользователя](#scenario1) \ -[Интеграция в существующий проект](#scenario2) \ -[Запуск примеров из репозитория](#scenario3) \ -[Сравнение производительности на различных устройствах](#scenario4) +1. [Установка](#установка) +2. [Проверка работоспособности](#проверка-работоспособности) +4. [Конфигурационный файл](#конфигурационный-файл) +5. [Настройка](#настройка) +6. [Профили](#профили) +7. [Наследование профилей (`extends`)](#наследование-профилей) -## Первоначальная настройка для нового пользователя +## Установка -Вы хотите выполнить минимальную настройку spla и получить работоспособное приложение. \ -Вы не знакомы с OpenCL, не знаете индексы своих GPU и не хотите разбираться в тонкостях конфигурации. +Инструкции по установке см. в [README](https://github.com/SparseLinearAlgebra/spla#installation). -По умолчанию spla требует явной настройки всех параметров. Без этого программа упадёт с ошибкой `IncompleteConfigError`. +## Проверка работоспособности -### Решение +После установки выполните команду, которая подтверждает, что библиотека готова к использованию. -Используйте следующую конфигурацию в коде. Скорее всего эти параметры вам подойдут. +```bash +spla --softcheck +``` +Команда выполняет следующую последовательность действий: + +1. Читает конфигурационный файл, предоставляющийся библиотекой. +2. Инициализирует OpenCL, выбирает платформу и устройство. +4. Запускает простое тестовое задание. +5. Сообщает статус. + +Пример успешного вывода: +```bash +$ spla --softcheck +[spla:check] Starting sanity check... +[spla:check] Loading factory config: /usr/share/spla/spla_conf.json +[spla:check] Initializing OpenCL... +[spla:check] Selected platform: NVIDIA CUDA +[spla:check] Selected device: NVIDIA GeForce RTX 3080 +[spla:check] Running test kernel: 2 + 3 = ... +[spla:check] Result: 5 (expected 5) +[spla:check] SUCCESS - spla works correctly +``` -```cpp -#include +## Конфигурационный файл +Конфигурационный файл, предоставляющийся библиотекой, имеет следующую структуру: -int main(int argc, char* argv[]) { - Config cfg; - cfg.platform = 0; - cfg.device = 0; - cfg.queues = 1; - cfg.prifiling = false; - cfg.allocator = "general"; - cfg.verbosity = 1; - - init(); - - return 0; +```json +{ + "execution": { + "target": "auto", + "on_unavailable": "fallback", + "platform": 0, + "device": 0 + }, + + "queues": 1, + "profiling": false, + "allocator": "general", + "allocator_size": 0, + "verbosity": 2, + "profile": null, + "profiles": {} } ``` +| Параметр | Тип | Значения в конфигурационном файле по умолчанию | Назначение | Допустимые значения | +| :--- | :--- | :--- | :--- | :--- | +| execution.target | string | "auto" | На каком устройстве работать | `gpu` - только GPU
`cpu` - только CPU
`auto` - GPU если доступен, иначе CPU | +| execution.on_unavailable | string | "fallback" | Что делать, если GPU недоступен | `fallback` - переключиться на CPU
`fail` - вернуть ошибку | +| execution.platform | int | 0 | Индекс OpenCL платформы | ≥ 0 | +| execution.device | int | 0 | Индекс GPU в платформе | ≥ 0 | +| queues | int | 1 | Число командных очередей | ≥ 1 | +| profiling | bool | false | Профилирование очередей | true / false | +| allocator | string | "general" | Тип аллокатора | general, linear | +| allocator_size | int | 0 | Размер линейного аллокатора (байт) | ≥ 0 (игнорируется для `general`) | +| verbosity | int | 2 | Уровень логирования | `0` - нет вывода
`1` - только ошибки
`2` - ошибки, предупреждения
`3` - ошибки, предупреждения, дополнительная информация | +| profile | string / null | null | Выбранный профиль | имя профиля из profiles или `null` | +| profiles | object | {} | Словарь профилей | { "name": { ... override ... } } | +| profiles.< name >.extends | array of string | [] | Список профилей-родителей | имена профилей из profiles | + +## Настройка + +Если параметры по умолчанию вас не устраивают, вы можете настроить библиотеку. Способы конфигурирования перечислены в порядке убывания приоритета: + +1. Аргументы командной строки. +2. Переменные окружения. +3. Пользовательский конфигурационный файл. +4. Системный конфигурационный файл. +5. Конфигурационный файл, поставляющийся библиотекой. + +### Расположение конфигурационных файлов + +Конфигурационный файл с параметрами по умолчанию: +>Linux `/usr/share/spla/spla_conf.json` \ +macOS `/usr/local/share/spla/spla_conf.json` \ +Windows `%ProgramData%\spla\spla_conf.json` + +Системный конфигурационный файл: +>Linux: `/etc/spla/spla_conf.json` \ +macOS: `/Library/Application Support/spla/spla_conf.json` \ +Windows: `%ProgramData%\spla\spla_conf.json` + +Пользовательский конфигурационный файл: +>Linux: `~/.config/spla/spla_conf.json` \ +macOS: `~/Library/Application Support/spla/spla_conf.json` \ +Windows: `%APPDATA%\spla\spla_conf.json` + + +## Профили + +Профили позволяют хранить несколько наборов настроек в одном конфигурационном файле и переключаться между ними при запуске. Это удобно, когда одну и ту же программу нужно запускать в разных режимах - например, на разных GPU или с разным уровнем логирования. + +- В конфигурационном файле описываются общие настройки, которые берутся в качестве базовых параметров. +- Описывается секция `profiles` - именованные наборы параметров. +- При запуске указывается имя профиля. +- Библиотека переопределяет базовые параметры параметрами из выбранного профиля. + +### Пример +```json +{ + "execution": { + "device": 0 + }, + "verbosity": 2, + "queues": 1, + + "profiles": { + "gpu0": { "execution": { "device": 0 } }, + "gpu1": { "execution": { "device": 1 } }, + "gpu2": { "execution": { "device": 2 } }, + "debug": { "verbosity": 3 }, + "bench": { "verbosity": 0 } + } +} +``` +### Запуск +```bash +SPLA_PROFILE=gpu1 ./program +SPLA_PROFILE=debug ./program +SPLA_PROFILE=bench ./program +``` +Или через CLI: +```bash +./program --spla-profile=gpu1 +``` +### Итоговый конфигурационный файл +```json +{ + "execution": { + "device": 1 + }, -## Запуск примеров из репозитория + "queues": 1, + "verbosity": 2, +} +``` + +## Наследование профилей -Вы хотите запустить примеры из репозитория, но не знаете, с какими значениями. +Иногда профили пересекаются по смыслу - например, **debug_gpu1** должен включать и режим отладки, и выбор GPU 1. Чтобы не дублировать параметры, профиль может наследовать другие профили через поле `extends`. -### Решение +- Если профиль содержит поле `extends`, библиотека сначала применяет указанные в нём профили по порядку. +- Затем к базовым параметрам применяются параметры каждого родительского профиля по очереди: последний в списке переопределяет предыдущие. +- После этого применяются параметры самого выбранного профиля, которые переопределяют всё, что было задано раньше. -Используйте переменные окружения со следующими параметрами. Скорее всего они вам подойдут. +### Пример +``` json +{ + "execution": { "device": 0 }, + "verbosity": 2, + + "profiles": { + "gpu0": { "execution": { "device": 0 } }, + "gpu1": { "execution": { "device": 1 } }, + "gpu2": { "execution": { "device": 2 } }, + + "debug": { "verbosity": 3, "profiling": true }, + "bench": { "verbosity": 0 }, + + "debug_gpu1": { + "extends": ["debug", "gpu1"] + }, + "bench_gpu2": { + "extends": ["bench", "gpu2"] + } + } +} +``` +### Запуск ```bash -export SPLA_PLATFORM=0 -export SPLA_DEVICE=0 -export SPLA_QUEUES=1 -export SPLA_PROFILING=false -export SPLA_ALLOCATOR=general -export SPLA_VERBOSITY=1 +SPLA_PROFILE=debug_gpu1 ./program +SPLA_PROFILE=bench_gpu2 ./program +``` +Или через CLI: +```bash +./program --spla-profile=debug_gpu1 ``` +### Итоговый конфигурационный файл +```json +{ + "execution": { "device": 1 }, + "verbosity": 3, + "profiling": true +} +``` -## Интеграция в существующий проект +--- +--- -Вы хотите внедрить spla в существующий проект, который уже имеет сложную структуру и обработку аргументов командной строки. +# Распространенные сценарии использования библиотеки + 1. Быстрый запуск без настройки. + 4. Многократный запуск на разных устройствах с разными параметрами. -Вы не хотите: +## Быстрый запуск без настройки -- Менять main() ради spla -- Добавлять в код жестко заданные значения -- Переписывать парсер аргументов +Если вы хотите получить работоспособное приложение без настройки - ничего настраивать не нужно. Библиотека использует параметры по умолчанию из [конфигурационного файла](#конфигурационный-файл). -### Решение +Этот сценарий работает одинаково на Linux, macOS и Windows. Если GPU недоступен, библиотека автоматически переключится на CPU, сообщив об этом. -Используйте переменные окружения или конфигурационные файлы. Они не требуют изменения кода. +Перед первым запуском рекомендуется [выполнить](#проверка-работоспособности) `spla --softcheck`, чтобы убедиться, что всё необходимое для работы spla установлено. -**Вариант A: Переменные окружения** \ -Пример конфигурации: +## Многократный запуск на разных устройствах с разными параметрами -```bash -export SPLA_PLATFORM=0 -export SPLA_DEVICE=0 -export SPLA_QUEUES=2 -export SPLA_PROFILING=false -export SPLA_ALLOCATOR=general -export SPLA_VERBOSITY=1 -``` -Подходят для разового запуска. +Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо того чтобы держать несколько конфигурационных файлов, вы описываете всё в одном. -**Вариант B: Конфигурационный файл** \ -Пример конфигурации: +Подробнее в главе про [профили](#профили) и [наследование профилей (`extends`)](#наследование-профилей). ```json { - "platform": 0, - "device": 0, - "queues": 2, - "profiling": false, - "allocator": "general", - "verbosity": 1 -} -``` -Подходят для многократного запуска. - + "execution": { "device": 0 }, + "verbosity": 2, -## Сравнение производительности на различных устройствах + "profiles": { + "gpu0": { "execution": { "device": 0 } }, + "gpu1": { "execution": { "device": 1 } }, + "gpu2": { "execution": { "device": 2 } }, -Вы хотите выбрать лучшее устройство для вашей задачи, сравнить производительность CPU, GPU, разных GPU, разных аллокаторов. + "debug": { "verbosity": 3, "profiling": true }, + "bench": { "verbosity": 0 }, -### РЕШЕНИЕ - -Используйте профилирование --spla-profiling = true + "debug_gpu1": { "extends": ["debug", "gpu1"] }, + "bench_gpu2": { "extends": ["bench", "gpu2"] } + } +} +``` \ No newline at end of file From ac5f337606216c74054c3d2bab5f93b8cf615f7c Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Fri, 25 Sep 2026 11:45:58 +0300 Subject: [PATCH 39/57] chanjed config structure --- src/opencl/UserGuide.md | 86 ++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 921dcbefe..454d441cb 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -6,10 +6,10 @@ 1. [Установка](#установка) 2. [Проверка работоспособности](#проверка-работоспособности) -4. [Конфигурационный файл](#конфигурационный-файл) -5. [Настройка](#настройка) -6. [Профили](#профили) -7. [Наследование профилей (`extends`)](#наследование-профилей) +3. [Конфигурационный файл](#конфигурационный-файл) +4. [Настройка](#настройка) +5. [Профили](#профили) +6. [Наследование профилей (`extends`)](#наследование-профилей) ## Установка @@ -47,34 +47,35 @@ $ spla --softcheck ```json { - "execution": { - "target": "auto", - "on_unavailable": "fallback", - "platform": 0, - "device": 0 - }, + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", - "queues": 1, + "platform_index": null, + "device_index": null, + + "queues_count": 1, "profiling": false, - "allocator": "general", - "allocator_size": 0, + "allocator_type": "general", + "linear_alloc_size": 0, + "verbosity": 2, + "profile": null, "profiles": {} } ``` -| Параметр | Тип | Значения в конфигурационном файле по умолчанию | Назначение | Допустимые значения | +| Параметр | Тип | Значение по умолчанию | Описание | Допустимые значения | | :--- | :--- | :--- | :--- | :--- | -| execution.target | string | "auto" | На каком устройстве работать | `gpu` - только GPU
`cpu` - только CPU
`auto` - GPU если доступен, иначе CPU | -| execution.on_unavailable | string | "fallback" | Что делать, если GPU недоступен | `fallback` - переключиться на CPU
`fail` - вернуть ошибку | -| execution.platform | int | 0 | Индекс OpenCL платформы | ≥ 0 | -| execution.device | int | 0 | Индекс GPU в платформе | ≥ 0 | -| queues | int | 1 | Число командных очередей | ≥ 1 | +| backend | string | "gpu" | На каком устройстве работать | `gpu` - только GPU
`cpu` - только CPU
`any` - любое доступное устройство
`by_index` - выбрать по индексам ниже | +| if_gpu_unavailable | string | "use_cpu" | Что делать, если GPU недоступен
Не применяется при backend: "`cpu`" или backend: "`by_index`" | `use_cpu` - переключиться на CPU
`abort` - вернуть ошибку | +| platform_index | int/null | null | Индекс OpenCL платформы
Используются только при backend: "`by_index`"
При других значениях backend - игнорируются | ≥ 0, null | +| device_index | int/null | null | Индекс устройства внутри платформы
Используются только при backend: "`by_index`"
При других значениях backend - игнорируются | ≥ 0, null | +| queues_count | int | 1 | Число командных очередей | ≥ 1 | | profiling | bool | false | Профилирование очередей | true / false | -| allocator | string | "general" | Тип аллокатора | general, linear | -| allocator_size | int | 0 | Размер линейного аллокатора (байт) | ≥ 0 (игнорируется для `general`) | +| allocator_type | string | "general" | Тип аллокатора | general, linear | +| linear_alloc_size | int | 0 | Размер линейного аллокатора (байт) | ≥ 0 (игнорируется для `general`) | | verbosity | int | 2 | Уровень логирования | `0` - нет вывода
`1` - только ошибки
`2` - ошибки, предупреждения
`3` - ошибки, предупреждения, дополнительная информация | -| profile | string / null | null | Выбранный профиль | имя профиля из profiles или `null` | +| profile | string/null | null | Выбранный профиль | имя профиля из profiles или `null` | | profiles | object | {} | Словарь профилей | { "name": { ... override ... } } | | profiles.< name >.extends | array of string | [] | Список профилей-родителей | имена профилей из profiles | @@ -212,15 +213,48 @@ SPLA_PROFILE=bench_gpu2 ./program # Распространенные сценарии использования библиотеки 1. Быстрый запуск без настройки. - 4. Многократный запуск на разных устройствах с разными параметрами. + 2. Выбор между CPU и GPU без указания индексов. + 3. Многократный запуск на разных устройствах с разными параметрами. ## Быстрый запуск без настройки -Если вы хотите получить работоспособное приложение без настройки - ничего настраивать не нужно. Библиотека использует параметры по умолчанию из [конфигурационного файла](#конфигурационный-файл). +Если вы хотите получить работоспособное приложение без настройки - ничего настраивать не нужно. Библиотека использует параметры по умолчанию из [конфигурационного файла](#конфигурационный-файл). Этот сценарий работает одинаково на Linux, macOS и Windows. Если GPU недоступен, библиотека автоматически переключится на CPU, сообщив об этом. \ +Перед первым запуском рекомендуется [выполнить](#проверка-работоспособности) `spla --softcheck`, чтобы убедиться, что всё необходимое для работы spla установлено. -Этот сценарий работает одинаково на Linux, macOS и Windows. Если GPU недоступен, библиотека автоматически переключится на CPU, сообщив об этом. +## Выбор между CPU и GPU без указания индексов -Перед первым запуском рекомендуется [выполнить](#проверка-работоспособности) `spla --softcheck`, чтобы убедиться, что всё необходимое для работы spla установлено. +Если вы хотите управлять типом устройства, но не указывать конкретные индексы OpenCL-платформ и устройств. + +### Управление через backend + +Тип устройства задаётся параметром backend +```json +{ "backend": "gpu" } //Использовать первое доступное GPU + +{ "backend": "cpu" } //Использовать CPU + +{ "backend": "any" } //Использовать первое доступное устройство любого типа +``` + +Индексы `platform_index` и `device_index` при этих значениях игнорируются. Это позволяет запускать программу на GPU или CPU без знания индексов. + +### Поведение при отсутствии GPU + +Если выбран backend: "gpu", но GPU недоступен, поведение определяется параметром `if_gpu_unavailable`: + +```json +{ + "backend": "gpu", + "if_gpu_unavailable": "use_cpu" //Библиотека переключается на CPU и продолжает работу +} + +{ + "backend": "gpu", + "if_gpu_unavailable": "abort" //Библиотека возвращает ошибку и не продолжает работу + //Стоит использовать, если требуется гарантировать выполнение на GPU +} +``` +`if_gpu_unavailable` применяется только при backend: "gpu" и backend: "any". При backend: "cpu" параметр игнорируется. ## Многократный запуск на разных устройствах с разными параметрами From 60f09aa15c7940cce3fce923afa5dae56d313673 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 28 Sep 2026 02:06:50 +0300 Subject: [PATCH 40/57] added new params to cnfig --- src/opencl/cl_accelerator.cpp | 31 ++-- src/opencl/cl_accelerator.hpp | 2 +- src/opencl/cl_configure.cpp | 306 +++++++++++++++++++--------------- src/opencl/cl_configure.hpp | 38 +++-- 4 files changed, 218 insertions(+), 159 deletions(-) diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index ef3f40538..0067ba881 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -44,8 +44,7 @@ namespace spla { InitResult result; result.config_status = configure(argc, argv); - if (result.config_status == ConfigStatus::HelpRequested || - result.config_status == ConfigStatus::VersionRequested) { + if (result.config_status == ConfigStatus::VersionRequested) { result.status = Status::Ok; return result; } @@ -67,13 +66,25 @@ namespace spla { Status CLAccelerator::init() { - int platform_index = config_final.platform.value(); - int device_index = config_final.device.value(); - int queues_count = config_final.queues.value(); + + std::string backend = config_final.backend.value(); + int platform_index; + int device_index; + if (backend == "by_index") { + platform_index = config_final.platform_index.value(); + device_index = config_final.device_index.value(); + } + std::string if_gpu_unavailable; + if (backend != "cpu") { + if_gpu_unavailable = config_final.if_gpu_unavailable.value(); + } + int queues_count = config_final.queues_count.value(); bool profiling = config_final.profiling.value(); - std::string allocator_type = config_final.allocator.value(); - size_t lin_allocator_size; - if (allocator_type == "linear") lin_allocator_size = config_final.allocator_size.value(); + std::string allocator_type = config_final.allocator_type.value(); + size_t linear_alloc_size; + if (allocator_type == "linear") { + linear_alloc_size = config_final.linear_alloc_size.value(); + } int verbosity = config_final.verbosity.value(); Library::get()->set_verbosity(verbosity); @@ -87,7 +98,7 @@ namespace spla { LOG_MSG(Status::Ok, " profiling = " << (profiling ? "true" : "false")); LOG_MSG(Status::Ok, " allocator = " << allocator_type); if (allocator_type == "linear") { - LOG_MSG(Status::Ok, " alloc_size= " << lin_allocator_size); + LOG_MSG(Status::Ok, " alloc_size= " << linear_alloc_size); } LOG_MSG(Status::Ok, " verbosity = " << verbosity); @@ -97,7 +108,7 @@ namespace spla { set_queues_count(queues_count); if (allocator_type == "linear") { - set_linear_allocator(lin_allocator_size); + set_linear_allocator(linear_alloc_size); } else { set_general_allocator(); } diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 1844dbcfe..13a882c69 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -55,7 +55,6 @@ #define SPLA_OPENCL_DEVICE "SPLA_OPENCL_DEVICE" namespace spla { - struct InitResult { Status status; ConfigStatus config_status; @@ -71,6 +70,7 @@ namespace spla { * @class CLAccelerator * @brief Single-device OpenCL acceleration implementation */ + class CLAccelerator final : public Accelerator { public: CLAccelerator(); diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 94ed1e99f..57ffb7eec 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -42,24 +42,28 @@ namespace spla { void Profile::merge(const Profile& src) { - if (src.platform.has_value()) platform = src.platform; - if (src.device.has_value()) device = src.device; - if (src.queues.has_value()) queues = src.queues; + if (src.backend.has_value()) backend = src.backend; + if (src.platform_index.has_value()) platform_index = src.platform_index; + if (src.device_index.has_value()) device_index = src.device_index; + if (src.if_gpu_unavailable.has_value()) if_gpu_unavailable = src.if_gpu_unavailable; + if (src.queues_count.has_value()) queues_count = src.queues_count; if (src.profiling.has_value()) profiling = src.profiling; - if (src.allocator.has_value()) allocator = src.allocator; - if (src.allocator_size.has_value()) allocator_size = src.allocator_size; + if (src.allocator_type.has_value()) allocator_type = src.allocator_type; + if (src.linear_alloc_size.has_value()) linear_alloc_size = src.linear_alloc_size; if (src.verbosity.has_value()) verbosity = src.verbosity; if (src.extends.has_value()) extends = src.extends; } void Config::merge(const Config& src) { - if (src.platform.has_value()) platform = src.platform; - if (src.device.has_value()) device = src.device; - if (src.queues.has_value()) queues = src.queues; + if (src.backend.has_value()) backend = src.backend; + if (src.platform_index.has_value()) platform_index = src.platform_index; + if (src.device_index.has_value()) device_index = src.device_index; + if (src.if_gpu_unavailable.has_value()) if_gpu_unavailable = src.if_gpu_unavailable; + if (src.queues_count.has_value()) queues_count = src.queues_count; if (src.profiling.has_value()) profiling = src.profiling; - if (src.allocator.has_value()) allocator = src.allocator; - if (src.allocator_size.has_value()) allocator_size = src.allocator_size; + if (src.allocator_type.has_value()) allocator_type = src.allocator_type; + if (src.linear_alloc_size.has_value()) linear_alloc_size = src.linear_alloc_size; if (src.verbosity.has_value()) verbosity = src.verbosity; if (src.profile.has_value()) profile = src.profile; @@ -171,46 +175,67 @@ namespace spla { ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg) { CLI::App app{"SPLA configuration"}; - app.add_flag("-sh,--spla-help", cfg.help, "Show help and exit"); + app.set_help_flag("-sh,--spla-help", "Show help and exit"); app.add_flag("-sv,--spla-version", cfg.version, "Show version and exit"); - app.add_option("-sp,--spla-platform", cfg.platform, + app.add_option("-sb,--spla-backend", cfg.backend, + "Device type to use:\n" + " gpu - only GPU\n" + " cpu - only CPU\n" + " any - any available device\n" + " by_index - select by platform_index and device_index\n" + "Config key: backend") + ->envname("SPLA_BACKEND"); + + app.add_option("-sp,--spla-platform-index", cfg.platform_index, "OpenCL platform index\n" - "Config key: platform") - ->envname("SPLA_OPENCL_PLATFORM"); + "Used only with backend=by_index.\n" + "Config key: platform_index") + ->envname("SPLA_PLATFORM_INDEX"); - app.add_option("-sd,--spla-device", cfg.device, + app.add_option("-sd,--spla-device-index", cfg.device_index, "OpenCL device index\n" - "Config key: device") - ->envname("SPLA_OPENCL_DEVICE"); - - app.add_option("-sq,--spla-queues", cfg.queues, + "Used only with backend=by_index.\n" + "Config key: device_index") + ->envname("SPLA_DEVICE_INDEX"); + + app.add_option("-sf,--spla-if-gpu-unavailable", cfg.if_gpu_unavailable, + "Behavior when GPU is unavailable:\n" + " use_cpu - switch to CPU\n" + " abort - return error\n" + "Config key: if_gpu_unavailable") + ->envname("SPLA_IF_GPU_UNAVAILABLE"); + + app.add_option("-sq,--spla-queues-count", cfg.queues_count, "Number of command queues\n" - "Config key: queues") - ->envname("SPLA_QUEUES"); + "Config key: queues_count") + ->envname("SPLA_QUEUES_COUNT"); app.add_flag("-pr,--spla-profiling", cfg.profiling, "Enable profiling of command queues\n" - "Config key: profiling\n") + "Config key: profiling") ->envname("SPLA_PROFILING"); - app.add_option("-sa,--spla-allocator", cfg.allocator, - "Allocator type: linear or general\n" - "Config key: allocator") - ->envname("SPLA_ALLOCATOR"); + app.add_option("-sa,--spla-allocator-type", cfg.allocator_type, + "Allocator type:\n" + " general\n" + " linear \n" + "Config key: allocator_type") + ->envname("SPLA_ALLOCATOR_TYPE"); - app.add_option("-as,--spla-allocator-size", cfg.allocator_size, + app.add_option("-as,--spla-linear-alloc-size", cfg.linear_alloc_size, "Linear allocator size in bytes\n" - "Required for 'linear' allocator. Ignored for 'general'.\n" - "Config key: allocator_size") - ->envname("SPLA_ALLOCATOR_SIZE"); + "Required for allocator_type=linear. Ignored for general.\n" + "Config key: linear_alloc_size") + ->envname("SPLA_LINEAR_ALLOC_SIZE"); app.add_option("-sV,--spla-verbosity", cfg.verbosity, "Verbosity level:\n" - " 0: No output\n" - " 1: Errors only\n" - " 2: Errors + warnings\n" - " 3: All messages (info, warnings, errors)") + " 0 - no output\n" + " 1 - errors only\n" + " 2 - errors and warnings\n" + " 3 - all messages\n" + "Config key: verbosity") ->envname("SPLA_VERBOSITY"); app.add_option("-sP,--spla-profile", cfg.profile, @@ -226,11 +251,6 @@ namespace spla { return ConfigStatus::CliOrEnvParseError; } - if (cfg.help) { - std::cout << app.help() << std::endl; - return ConfigStatus::HelpRequested; - } - if (cfg.version) { std::cout << get_spla_version() << std::endl; return ConfigStatus::VersionRequested; @@ -256,27 +276,43 @@ namespace spla { try { nlohmann::json data = nlohmann::json::parse(file); - if (data.contains("platform")) cfg.platform = data["platform"].get(); - if (data.contains("device")) cfg.device = data["device"].get(); - if (data.contains("queues")) cfg.queues = data["queues"].get(); + if (data.contains("backend")) cfg.backend = data["backend"].get(); + + if (data.contains("platform_index")) cfg.platform_index = data["platform_index"].get(); + if (data.contains("device_index")) cfg.device_index = data["device_index"].get(); + + if (data.contains("if_gpu_unavailable")) cfg.if_gpu_unavailable = data["if_gpu_unavailable"].get(); + + if (data.contains("queues_count")) cfg.queues_count = data["queues_count"].get(); if (data.contains("profiling")) cfg.profiling = data["profiling"].get(); - if (data.contains("allocator")) cfg.allocator = data["allocator"].get(); - if (data.contains("allocator_size")) cfg.allocator_size = data["allocator_size"].get(); + if (data.contains("allocator_type")) cfg.allocator_type = data["allocator_type"].get(); + if (data.contains("linear_alloc_size")) cfg.linear_alloc_size = data["linear_alloc_size"].get(); + if (data.contains("verbosity")) cfg.verbosity = data["verbosity"].get(); + if (data.contains("profile")) cfg.profile = data["profile"].get(); if (data.contains("profiles")) { std::map profiles; for (auto& [name, p] : data["profiles"].items()) { Profile prof; - if (p.contains("platform")) prof.platform = p["platform"].get(); - if (p.contains("device")) prof.device = p["device"].get(); - if (p.contains("queues")) prof.queues = p["queues"].get(); + + if (p.contains("backend")) prof.backend = p["backend"].get(); + + if (p.contains("platform_index")) prof.platform_index = p["platform_index"].get(); + if (p.contains("device_index")) prof.device_index = p["device_index"].get(); + + if (p.contains("if_gpu_unavailable")) prof.if_gpu_unavailable = p["if_gpu_unavailable"].get(); + + if (p.contains("queues_count")) prof.queues_count = p["queues_count"].get(); if (p.contains("profiling")) prof.profiling = p["profiling"].get(); - if (p.contains("allocator")) prof.allocator = p["allocator"].get(); - if (p.contains("allocator_size")) prof.allocator_size = p["allocator_size"].get(); + if (p.contains("allocator_type")) prof.allocator_type = p["allocator_type"].get(); + if (p.contains("linear_alloc_size")) prof.linear_alloc_size = p["linear_alloc_size"].get(); + if (p.contains("verbosity")) prof.verbosity = p["verbosity"].get(); + if (p.contains("extends")) prof.extends = p["extends"].get>(); + profiles[name] = prof; } cfg.profiles = profiles; @@ -292,113 +328,117 @@ namespace spla { } - ConfigStatus check_platform_and_device(int platform_index, int device_index) { + ConfigStatus validation(const Config& cfg) { + if (!cfg.backend.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: backend" << std::endl; + return ConfigStatus::MissedParameters; + } - if (platform_index < 0) { - std::cerr << "[spla:opencl] ERROR: platform must be >= 0 (got " - << platform_index << ")" << std::endl; + const std::string& backend = *cfg.backend; + if (backend != "gpu" && backend != "cpu" && + backend != "any" && backend != "by_index") { + std::cerr << "[spla:validation] ERROR: backend must be " + << "'gpu', 'cpu', 'any' or 'by_index' (got '" << backend << "')" << std::endl; return ConfigStatus::InvalidConfigParams; } - std::vector platforms; - cl::Platform::get(&platforms); + if (backend == "by_index") { + if (!cfg.platform_index.has_value()) { + std::cerr << "[spla:validation] ERROR: platform_index is required " + << "when backend='by_index'" << std::endl; + return ConfigStatus::MissedParameters; + } + if (!cfg.device_index.has_value()) { + std::cerr << "[spla:validation] ERROR: device_index is required " + << "when backend='by_index'" << std::endl; + return ConfigStatus::MissedParameters; + } - if (platforms.empty()) { - std::cerr << "[spla:opencl] ERROR: no platform available" << std::endl; - return ConfigStatus::PlatformNotFound; + if (cfg.platform_index < 0) { + std::cerr << "[spla:opencl] ERROR: platform must be >= 0 (got " + << *cfg.platform_index << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + if (cfg.device_index < 0) { + std::cerr << "[spla:opencl] ERROR: device must be >= 0 (got " + << *cfg.device_index << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } } - if (static_cast(platform_index) >= platforms.size()) { - std::cerr << "[spla:opencl] ERROR: platform index out of range (got " - << platform_index << ", max " << platforms.size() - 1 << ")" - << std::endl; - return ConfigStatus::PlatformNotFound; + if (backend != "cpu") { + if (!cfg.if_gpu_unavailable.has_value()) { + std::cerr << "[spla:validation] ERROR: if_gpu_unavailable is required " + << "when backend= 'any', 'gpu', 'by_index'" << std::endl; + return ConfigStatus::MissedParameters; + } + const std::string& behavior = *cfg.if_gpu_unavailable; + if (behavior != "use_cpu" && behavior != "abort") { + std::cerr << "[spla:validation] ERROR: if_gpu_unavailable must be " + << "'use_cpu' or 'abort' (got '" << behavior << "')" << std::endl; + return ConfigStatus::InvalidConfigParams; + } } - - if (device_index < 0) { - std::cerr << "[spla:opencl] ERROR: device must be >= 0 (got " - << device_index << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; + if (backend == "cpu" && cfg.if_gpu_unavailable.has_value()) { + std::cerr << "[spla:validation] WARNING: if_gpu_unavailable " + << "ignored for backend='" << backend << "'" << std::endl; } - std::vector devices; - platforms[platform_index].getDevices(CL_DEVICE_TYPE_ALL, &devices); - if (devices.empty()) { - std::cerr << "[spla:opencl] ERROR: no device available on platform " - << platform_index << std::endl; - return ConfigStatus::DeviceNotFound; + if (backend != "by_index") { + if (cfg.platform_index.has_value() || cfg.device_index.has_value()) { + std::cerr << "[spla:validation] WARNING: platform_index/device_index " + << "ignored for backend='" << backend << "'" << std::endl; + } } - if (static_cast(device_index) >= devices.size()) { - std::cerr << "[spla:opencl] ERROR: device index out of range (got " - << device_index << ", max " << devices.size() - 1 << ")" - << std::endl; - return ConfigStatus::DeviceNotFound; - } - return ConfigStatus::Ok; - } - - - ConfigStatus validation(const Config& cfg) { - - if (!cfg.platform.has_value()) { - std::cerr << "[spla:validation] ERROR: required: platform" << std::endl; - return ConfigStatus::MissedParameters; - } - if (!cfg.device.has_value()) { - std::cerr << "[spla:validation] ERROR: required: device" << std::endl; - return ConfigStatus::MissedParameters; - } - if (!cfg.queues.has_value()) { - std::cerr << "[spla:validation] ERROR: required: queues" << std::endl; + if (!cfg.queues_count.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: queues_count" << std::endl; return ConfigStatus::MissedParameters; } - if (!cfg.profiling.has_value()) { - std::cerr << "[spla:validation] ERROR: required: profiling" << std::endl; - return ConfigStatus::MissedParameters; - } - if (!cfg.allocator.has_value()) { - std::cerr << "[spla:validation] ERROR: required: allocator" << std::endl; - return ConfigStatus::MissedParameters; - } - if (!cfg.verbosity.has_value()) { - std::cerr << "[spla:validation] ERROR: required: verbosity" << std::endl; - return ConfigStatus::MissedParameters; + if (*cfg.queues_count <= 0) { + std::cerr << "[spla:validation] ERROR: queues_count must be > 0 (got " + << *cfg.queues_count << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; } - if (cfg.allocator.value() == "linear" && !cfg.allocator_size.has_value()) { - std::cerr << "[spla:validation] ERROR: allocator_size is required for 'linear' allocator" - << std::endl; + + if (!cfg.profiling.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: profiling" << std::endl; return ConfigStatus::MissedParameters; } - ConfigStatus status; - status = check_platform_and_device(*cfg.platform, *cfg.device); - if (status != ConfigStatus::Ok) { - return status; + if (!cfg.allocator_type.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: allocator_type" << std::endl; + return ConfigStatus::MissedParameters; } - - if (*cfg.queues <= 0) { - std::cerr << "[spla:validation] ERROR: queues must be > 0 (got " - << *cfg.queues << ")" << std::endl; + if (*cfg.allocator_type != "general" && *cfg.allocator_type != "linear") { + std::cerr << "[spla:validation] ERROR: allocator_type must be " + << "'general' or 'linear' (got '" << *cfg.allocator_type << "')" << std::endl; return ConfigStatus::InvalidConfigParams; } - if (*cfg.allocator != "linear" && *cfg.allocator != "general") { - std::cerr << "[spla:validation] ERROR: allocator must be 'linear' or 'general' (got '" - << *cfg.allocator << "')" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - if (*cfg.allocator == "linear" && *cfg.allocator_size <= 0) { - std::cerr << "[spla:validation] ERROR: allocator_size must be > 0 for 'linear' (got " - << *cfg.allocator_size << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; + if (*cfg.allocator_type == "linear") { + if (!cfg.linear_alloc_size.has_value()) { + std::cerr << "[spla:validation] ERROR: linear_alloc_size is required " + << "when allocator_type='linear'" << std::endl; + return ConfigStatus::MissedParameters; + } + if (*cfg.linear_alloc_size <= 0) { + std::cerr << "[spla:validation] ERROR: linear_alloc_size must be > 0 (got " + << *cfg.linear_alloc_size << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } } + + if (!cfg.verbosity.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: verbosity" << std::endl; + return ConfigStatus::MissedParameters; + } if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { std::cerr << "[spla:validation] ERROR: verbosity must be in [0, 3] (got " << *cfg.verbosity << ")" << std::endl; @@ -464,12 +504,14 @@ namespace spla { return ConfigStatus::ProfileNotFound; } - if (resolved.platform) cfg.platform = resolved.platform; - if (resolved.device) cfg.device = resolved.device; - if (resolved.queues) cfg.queues = resolved.queues; + if (resolved.backend) cfg.backend = resolved.backend; + if (resolved.if_gpu_unavailable) cfg.if_gpu_unavailable = resolved.if_gpu_unavailable; + if (resolved.platform_index) cfg.platform_index = resolved.platform_index; + if (resolved.device_index) cfg.device_index = resolved.device_index; + if (resolved.queues_count) cfg.queues_count = resolved.queues_count; if (resolved.profiling) cfg.profiling = resolved.profiling; - if (resolved.allocator) cfg.allocator = resolved.allocator; - if (resolved.allocator_size) cfg.allocator_size = resolved.allocator_size; + if (resolved.allocator_type) cfg.allocator_type = resolved.allocator_type; + if (resolved.linear_alloc_size) cfg.linear_alloc_size = resolved.linear_alloc_size; if (resolved.verbosity) cfg.verbosity = resolved.verbosity; return ConfigStatus::Ok; diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 6ddef1b2c..7f3f9ce89 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -45,12 +45,17 @@ namespace spla { struct Profile { - std::optional platform; - std::optional device; - std::optional queues; + std::optional backend; + + std::optional platform_index; + std::optional device_index; + + std::optional if_gpu_unavailable; + + std::optional queues_count; std::optional profiling; - std::optional allocator; - std::optional allocator_size; + std::optional allocator_type; + std::optional linear_alloc_size; std::optional verbosity; std::optional> extends; @@ -58,14 +63,19 @@ namespace spla { }; struct Config { - std::optional help; - std::optional version; - std::optional platform; - std::optional device; - std::optional queues; + std::optional version; + + std::optional backend; + + std::optional platform_index; + std::optional device_index; + + std::optional if_gpu_unavailable; + + std::optional queues_count; std::optional profiling; - std::optional allocator; - std::optional allocator_size; + std::optional allocator_type; + std::optional linear_alloc_size; std::optional verbosity; std::optional profile; @@ -79,7 +89,6 @@ namespace spla { enum ConfigStatus { Ok, - HelpRequested, VersionRequested, CliOrEnvParseError, @@ -90,8 +99,6 @@ namespace spla { ProfileCycle, MissedParameters, - PlatformNotFound, - DeviceNotFound, InvalidConfigParams }; @@ -111,7 +118,6 @@ namespace spla { ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg); ConfigStatus parse_file(const std::string& path, Config& cfg); - ConfigStatus check_platform_and_device(int platform_index, int device_index); ConfigStatus validation(const Config& cfg); Profile apply_extends(const std::map& profiles, From 7586978f5c2feb115adf9951bb143fe73f5c4153 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 28 Sep 2026 02:24:54 +0300 Subject: [PATCH 41/57] fixed build err --- src/opencl/cl_accelerator.hpp | 1 + src/opencl/cl_config_status.hpp | 47 +++++++++++++++++++++++++++++++++ src/opencl/cl_configure.hpp | 17 +----------- 3 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 src/opencl/cl_config_status.hpp diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 13a882c69..85e8abb21 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -37,6 +37,7 @@ #include #include +#include "cl_config_status.hpp" #ifndef SPLA_RELEASE #define CL_HPP_ENABLE_EXCEPTIONS diff --git a/src/opencl/cl_config_status.hpp b/src/opencl/cl_config_status.hpp new file mode 100644 index 000000000..be82a77cb --- /dev/null +++ b/src/opencl/cl_config_status.hpp @@ -0,0 +1,47 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/JetBrains-Research/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +namespace spla { + +enum ConfigStatus { + Ok, + HelpRequested, + VersionRequested, + CliOrEnvParseError, + ParseConfError, + OpenFileError, + ProfileNotFound, + ProfileCycle, + MissedParameters, + PlatformNotFound, + DeviceNotFound, + InvalidConfigParams +}; + +} // namespace spla \ No newline at end of file diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index 7f3f9ce89..b4ed2e460 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -35,6 +35,7 @@ #include "CLI/CLI.hpp" #include +#include "cl_config_status.hpp" #ifdef _WIN32 #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) @@ -86,22 +87,6 @@ namespace spla { }; - enum ConfigStatus { - Ok, - - VersionRequested, - CliOrEnvParseError, - - ParseConfError, - OpenFileError, - - ProfileNotFound, - ProfileCycle, - - MissedParameters, - InvalidConfigParams - }; - extern Config config_default; extern Config config_system; extern Config config_user; From ec9897a63bfe1d1fe3038191c28fd8e8d5ee0f5a Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 28 Sep 2026 02:57:37 +0300 Subject: [PATCH 42/57] CL_TARGET_OPENCL_VERSION=300 -> 120 back --- CMakeLists.txt | 24 ++++++++++++------- .../tests/pkgconfig/bare/CMakeLists.txt | 2 +- .../tests/pkgconfig/sdk/CMakeLists.txt | 2 +- .../test/pkgconfig/bare/CMakeLists.txt | 2 +- .../test/pkgconfig/pkgconfig/CMakeLists.txt | 2 +- .../test/pkgconfig/sdk/CMakeLists.txt | 2 +- 6 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 334095e71..2891ef6c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,6 +206,13 @@ if (SPLA_BUILD_OPENCL) add_library(OpenCL INTERFACE) target_include_directories(OpenCL INTERFACE ${OpenCL_INCLUDE_DIRS}) target_link_libraries(OpenCL INTERFACE ${OpenCL_LIBRARIES}) + + # HPP bindings — из системного framework + message(STATUS "Use system OpenCL HPP bindings (macOS)") + add_library(HeadersCpp INTERFACE) + add_library(OpenCL::HeadersCpp ALIAS HeadersCpp) + target_include_directories(HeadersCpp INTERFACE ${OpenCL_INCLUDE_DIRS}) + target_link_libraries(HeadersCpp INTERFACE OpenCL::Headers) else () message(STATUS "Add Khronos OpenCL C API header files") add_subdirectory(deps/opencl-headers) @@ -215,14 +222,14 @@ if (SPLA_BUILD_OPENCL) set(OPENCL_ICD_LOADER_BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) set(OPENCL_ICD_LOADER_BUILD_TESTING OFF CACHE BOOL "" FORCE) add_subdirectory(deps/opencl-icd-loader) - endif () - - message(STATUS "Add Khronos OpenCL HPP bindings") - add_library(HeadersCpp INTERFACE) - add_library(OpenCL::HeadersCpp ALIAS HeadersCpp) - target_include_directories(HeadersCpp INTERFACE deps/opencl-headers-hpp/include) - target_link_libraries(HeadersCpp INTERFACE OpenCL::Headers) + # HPP bindings — из deps (только для Linux/Windows) + message(STATUS "Add Khronos OpenCL HPP bindings") + add_library(HeadersCpp INTERFACE) + add_library(OpenCL::HeadersCpp ALIAS HeadersCpp) + target_include_directories(HeadersCpp INTERFACE deps/opencl-headers-hpp/include) + target_link_libraries(HeadersCpp INTERFACE OpenCL::Headers) + endif () endif () if (SPLA_BUILD_EXAMPLES) @@ -251,6 +258,7 @@ set(SRC_OPENCL) if (SPLA_BUILD_OPENCL) set(SRC_OPENCL + src/opencl/cl_config_status.hpp src/opencl/cl_configure.cpp src/opencl/cl_configure.hpp src/opencl/cl_debug.hpp @@ -395,7 +403,7 @@ target_link_libraries(spla PRIVATE nlohmann_json::nlohmann_json) if (SPLA_BUILD_OPENCL) target_link_libraries(spla PUBLIC OpenCL) target_link_libraries(spla PUBLIC OpenCL::HeadersCpp) - target_compile_definitions(spla PUBLIC CL_TARGET_OPENCL_VERSION=300) + target_compile_definitions(spla PUBLIC CL_TARGET_OPENCL_VERSION=120) list(APPEND SPLA_DEFINES SPLA_BUILD_OPENCL) endif () diff --git a/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt b/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt index b7a535f91..f3e8466ee 100644 --- a/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt +++ b/deps/opencl-headers/tests/pkgconfig/bare/CMakeLists.txt @@ -19,7 +19,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=300 + CL_TARGET_OPENCL_VERSION=120 ) include(CTest) diff --git a/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt b/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt index 5b0bb6d37..aa36d168b 100644 --- a/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt +++ b/deps/opencl-headers/tests/pkgconfig/sdk/CMakeLists.txt @@ -20,7 +20,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=300 + CL_TARGET_OPENCL_VERSION=120 ) include(CTest) diff --git a/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt b/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt index f9120c2bf..f58f21e9e 100644 --- a/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt +++ b/deps/opencl-icd-loader/test/pkgconfig/bare/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=300 + CL_TARGET_OPENCL_VERSION=120 ) include(CTest) diff --git a/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt b/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt index 221153e79..436fffdb4 100644 --- a/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt +++ b/deps/opencl-icd-loader/test/pkgconfig/pkgconfig/CMakeLists.txt @@ -39,7 +39,7 @@ target_compile_options(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=300 + CL_TARGET_OPENCL_VERSION=120 ) include(CTest) diff --git a/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt b/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt index 1b2021e1f..83a52b70b 100644 --- a/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt +++ b/deps/opencl-icd-loader/test/pkgconfig/sdk/CMakeLists.txt @@ -24,7 +24,7 @@ target_link_libraries(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - CL_TARGET_OPENCL_VERSION=300 + CL_TARGET_OPENCL_VERSION=120 ) include(CTest) From 788e7b4878340f56fa5d0a175f45df0aed25723e Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 28 Sep 2026 03:22:38 +0300 Subject: [PATCH 43/57] fixed CL_HPP_MINIMUM_OPENCL_VERSION --- src/opencl/cl_config_status.hpp | 30 +++++++++++++++--------------- src/opencl/cl_configure.cpp | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/opencl/cl_config_status.hpp b/src/opencl/cl_config_status.hpp index be82a77cb..bfcd9dfab 100644 --- a/src/opencl/cl_config_status.hpp +++ b/src/opencl/cl_config_status.hpp @@ -29,19 +29,19 @@ namespace spla { -enum ConfigStatus { - Ok, - HelpRequested, - VersionRequested, - CliOrEnvParseError, - ParseConfError, - OpenFileError, - ProfileNotFound, - ProfileCycle, - MissedParameters, - PlatformNotFound, - DeviceNotFound, - InvalidConfigParams -}; + enum ConfigStatus { + Ok, + HelpRequested, + VersionRequested, + CliOrEnvParseError, + ParseConfError, + OpenFileError, + ProfileNotFound, + ProfileCycle, + MissedParameters, + PlatformNotFound, + DeviceNotFound, + InvalidConfigParams + }; -} // namespace spla \ No newline at end of file +}// namespace spla \ No newline at end of file diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp index 57ffb7eec..72bac90c2 100644 --- a/src/opencl/cl_configure.cpp +++ b/src/opencl/cl_configure.cpp @@ -26,7 +26,6 @@ /**********************************************************************************/ #include "cl_configure.hpp" -#include "CL/opencl.hpp" #include "cl_accelerator.hpp" #include From b895cd97e1baf9ecf0762b4d17d10e5a3c42720b Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 28 Sep 2026 03:42:37 +0300 Subject: [PATCH 44/57] for deps --- CMakeLists.txt | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2891ef6c2..2ef13ccc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,23 +196,22 @@ FetchContent_MakeAvailable(nlohmann_json) if (SPLA_BUILD_OPENCL) if (SPLA_TARGET_MACOSX) - message(STATUS "Add standard Apple OpenCL package") - find_package(OpenCL REQUIRED) + message(STATUS "Use Apple OpenCL framework for linking, headers from deps") + find_library(OPENCL_FRAMEWORK OpenCL REQUIRED) add_library(OpenCLHeaders INTERFACE) add_library(OpenCL::Headers ALIAS OpenCLHeaders) - target_include_directories(OpenCLHeaders INTERFACE ${OpenCL_INCLUDE_DIRS}) + target_include_directories(OpenCLHeaders INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/deps/opencl-headers) - add_library(OpenCL INTERFACE) - target_include_directories(OpenCL INTERFACE ${OpenCL_INCLUDE_DIRS}) - target_link_libraries(OpenCL INTERFACE ${OpenCL_LIBRARIES}) - - # HPP bindings — из системного framework - message(STATUS "Use system OpenCL HPP bindings (macOS)") add_library(HeadersCpp INTERFACE) add_library(OpenCL::HeadersCpp ALIAS HeadersCpp) - target_include_directories(HeadersCpp INTERFACE ${OpenCL_INCLUDE_DIRS}) + target_include_directories(HeadersCpp INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/deps/opencl-headers-hpp/include) target_link_libraries(HeadersCpp INTERFACE OpenCL::Headers) + + add_library(OpenCL INTERFACE) + target_link_libraries(OpenCL INTERFACE ${OPENCL_FRAMEWORK}) else () message(STATUS "Add Khronos OpenCL C API header files") add_subdirectory(deps/opencl-headers) @@ -403,7 +402,10 @@ target_link_libraries(spla PRIVATE nlohmann_json::nlohmann_json) if (SPLA_BUILD_OPENCL) target_link_libraries(spla PUBLIC OpenCL) target_link_libraries(spla PUBLIC OpenCL::HeadersCpp) - target_compile_definitions(spla PUBLIC CL_TARGET_OPENCL_VERSION=120) + target_compile_definitions(spla PUBLIC + CL_TARGET_OPENCL_VERSION=120 + CL_HPP_TARGET_OPENCL_VERSION=120 + CL_HPP_MINIMUM_OPENCL_VERSION=120) list(APPEND SPLA_DEFINES SPLA_BUILD_OPENCL) endif () From 3e7f8175a0727ea7d3f2eb5bd4aeb42d4ad8778a Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Mon, 28 Sep 2026 03:42:50 +0300 Subject: [PATCH 45/57] for formatter --- src/opencl/cl_accelerator.hpp | 2 +- src/opencl/cl_configure.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 85e8abb21..0790c5e5e 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -36,8 +36,8 @@ #include #include -#include #include "cl_config_status.hpp" +#include #ifndef SPLA_RELEASE #define CL_HPP_ENABLE_EXCEPTIONS diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp index b4ed2e460..a51200801 100644 --- a/src/opencl/cl_configure.hpp +++ b/src/opencl/cl_configure.hpp @@ -34,8 +34,8 @@ #include #include "CLI/CLI.hpp" -#include #include "cl_config_status.hpp" +#include #ifdef _WIN32 #elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) From 17ec47a085fa9b94600aae3b8923b5f2305dd92b Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Sun, 4 Oct 2026 02:31:54 +0300 Subject: [PATCH 46/57] removed base from UserGuide --- src/opencl/UserGuide.md | 369 ++++++++++++++++++++++++++-------------- 1 file changed, 237 insertions(+), 132 deletions(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 454d441cb..40d0a9470 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -8,8 +8,8 @@ 2. [Проверка работоспособности](#проверка-работоспособности) 3. [Конфигурационный файл](#конфигурационный-файл) 4. [Настройка](#настройка) -5. [Профили](#профили) -6. [Наследование профилей (`extends`)](#наследование-профилей) +5. [Конфигурации](#конфигурации) +6. [Наследование конфигураций (`extends`)](#наследование-конфигураций) ## Установка @@ -33,7 +33,6 @@ spla --softcheck ```bash $ spla --softcheck [spla:check] Starting sanity check... -[spla:check] Loading factory config: /usr/share/spla/spla_conf.json [spla:check] Initializing OpenCL... [spla:check] Selected platform: NVIDIA CUDA [spla:check] Selected device: NVIDIA GeForce RTX 3080 @@ -43,41 +42,53 @@ $ spla --softcheck ``` ## Конфигурационный файл -Конфигурационный файл, предоставляющийся библиотекой, имеет следующую структуру: +Файл конфигурации `spla_conf.json` состоит из двух частей: +- `current_config` - имя конфигурации, которую вы хотите применить; + +- `configs` - словарь именованных конфигураций. + +Каждая конфигурация - это именованный набор параметров библиотеки. Все параметры библиотеки описываются внутри конфигураций. + +Файл конфигурации, предоставляющийся библиотекой, имеет следующую структуру: ```json { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu", - - "platform_index": null, - "device_index": null, + "current_config": "default", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "linear_alloc_size": 0, + "configs": { + "default": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", - "verbosity": 2, + "queues_count": 1, + "profiling": false, + "allocator_type": "general", - "profile": null, - "profiles": {} + "verbosity": 2 + } + } } ``` -| Параметр | Тип | Значение по умолчанию | Описание | Допустимые значения | -| :--- | :--- | :--- | :--- | :--- | -| backend | string | "gpu" | На каком устройстве работать | `gpu` - только GPU
`cpu` - только CPU
`any` - любое доступное устройство
`by_index` - выбрать по индексам ниже | -| if_gpu_unavailable | string | "use_cpu" | Что делать, если GPU недоступен
Не применяется при backend: "`cpu`" или backend: "`by_index`" | `use_cpu` - переключиться на CPU
`abort` - вернуть ошибку | -| platform_index | int/null | null | Индекс OpenCL платформы
Используются только при backend: "`by_index`"
При других значениях backend - игнорируются | ≥ 0, null | -| device_index | int/null | null | Индекс устройства внутри платформы
Используются только при backend: "`by_index`"
При других значениях backend - игнорируются | ≥ 0, null | -| queues_count | int | 1 | Число командных очередей | ≥ 1 | -| profiling | bool | false | Профилирование очередей | true / false | -| allocator_type | string | "general" | Тип аллокатора | general, linear | -| linear_alloc_size | int | 0 | Размер линейного аллокатора (байт) | ≥ 0 (игнорируется для `general`) | -| verbosity | int | 2 | Уровень логирования | `0` - нет вывода
`1` - только ошибки
`2` - ошибки, предупреждения
`3` - ошибки, предупреждения, дополнительная информация | -| profile | string/null | null | Выбранный профиль | имя профиля из profiles или `null` | -| profiles | object | {} | Словарь профилей | { "name": { ... override ... } } | -| profiles.< name >.extends | array of string | [] | Список профилей-родителей | имена профилей из profiles | + +### Параметры верхнего уровня +| Параметр | Тип | Описание | Допустимые значения | +| :--- | :--- | :--- | :--- | +| current_config | string | Имя применяемой конфигурации | имя из `configs` (со всех уровней) | +| configs | object | Словарь именованных конфигураций | { "name": { ... } } | + +### Параметры конфигурации +| Параметр | Тип | Описание | Допустимые значения | +| :--- | :--- | :--- | :--- | +| extends | array of string | Список конфигураций-родителей | имена из `configs` (со всех уровней) | +| backend | string | На каком устройстве работать | `"gpu"` - только GPU
`"cpu"` - только CPU
`"any"` - любое доступное устройство
`"by_index"` - выбрать по индексам ниже | +| platform_index | int | Индекс OpenCL платформы
Используются только при backend: `"by_index"`
При других значениях backend - игнорируются | ≥ 0 | +| device_index | int | Индекс устройства внутри платформы
Используются только при backend: `"by_index"`
При других значениях backend - игнорируются | ≥ 0 | +| if_gpu_unavailable | string | Что делать, если GPU недоступен
Не применяется при backend: `"cpu"` | `"use_cpu"` - переключиться на CPU
`"abort"` - вернуть ошибку
| +| queues_count | int | Число командных очередей | ≥ 1 | +| profiling | bool | Профилирование очередей | true, false | +| allocator_type | string | Тип аллокатора | `"general"`, `"linear"` | +| linear_alloc_size | int | Размер линейного аллокатора (байт)
Используются только при allocator_type: `"linear"` | ≥ 0 | +| verbosity | int | Уровень логирования | `0` - нет вывода,
`1` - только ошибки,
`2` - ошибки, предупреждения,
`3` - ошибки, предупреждения, дополнительная информация | ## Настройка @@ -91,123 +102,184 @@ $ spla --softcheck ### Расположение конфигурационных файлов -Конфигурационный файл с параметрами по умолчанию: ->Linux `/usr/share/spla/spla_conf.json` \ -macOS `/usr/local/share/spla/spla_conf.json` \ -Windows `%ProgramData%\spla\spla_conf.json` +**Конфигурационный файл с параметрами по умолчанию:** -Системный конфигурационный файл: +Файл конфигурации с параметрами по умолчанию поставляется вместе с пакетом pyspla и располагается внутри директории установленного Python-пакета. +Расположение зависит от способа установки пакета (глобально, --user, в виртуальном окружении). + +**Системный конфигурационный файл:** >Linux: `/etc/spla/spla_conf.json` \ macOS: `/Library/Application Support/spla/spla_conf.json` \ Windows: `%ProgramData%\spla\spla_conf.json` -Пользовательский конфигурационный файл: +**Пользовательский конфигурационный файл:** >Linux: `~/.config/spla/spla_conf.json` \ macOS: `~/Library/Application Support/spla/spla_conf.json` \ Windows: `%APPDATA%\spla\spla_conf.json` -## Профили - -Профили позволяют хранить несколько наборов настроек в одном конфигурационном файле и переключаться между ними при запуске. Это удобно, когда одну и ту же программу нужно запускать в разных режимах - например, на разных GPU или с разным уровнем логирования. +## Конфигурации -- В конфигурационном файле описываются общие настройки, которые берутся в качестве базовых параметров. -- Описывается секция `profiles` - именованные наборы параметров. -- При запуске указывается имя профиля. -- Библиотека переопределяет базовые параметры параметрами из выбранного профиля. +Конфигурации позволяют хранить несколько наборов настроек в одном файле конфигурации и переключаться между ними при запуске. Это удобно, когда одну и ту же программу нужно запускать в разных режимах. -### Пример +### Пример конфигурационного файла ```json { - "execution": { - "device": 0 - }, - "verbosity": 2, - "queues": 1, - - "profiles": { - "gpu0": { "execution": { "device": 0 } }, - "gpu1": { "execution": { "device": 1 } }, - "gpu2": { "execution": { "device": 2 } }, - "debug": { "verbosity": 3 }, - "bench": { "verbosity": 0 } + "configs": { + + "cpu": { + "backend": "cpu", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 2 + }, + "gpu0": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", + "queues_count": 2, + "profiling": true, + "allocator_type": "linear", + "linear_alloc_size": 8, + "verbosity": 0 + }, + "gpu1": { + "backend": "by_index", + "platform_index": 0, + "device_index": 2, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 3 + } } } ``` ### Запуск ```bash -SPLA_PROFILE=gpu1 ./program -SPLA_PROFILE=debug ./program -SPLA_PROFILE=bench ./program +SPLA_CONFIG=cpu ./program +SPLA_CONFIG=gpu0 ./program +SPLA_CONFIG=gpu1 ./program ``` Или через CLI: ```bash -./program --spla-profile=gpu1 +./program --spla-config=gpu1 ``` +## Наследование конфигураций -### Итоговый конфигурационный файл -```json -{ - "execution": { - "device": 1 - }, +Иногда конфигурации пересекаются по смыслу - например, `debug_gpu1` должна включать и `режим отладки`, и `выбор GPU 1`. Чтобы не дублировать параметры, конфигурация может наследовать другие конфигурации через поле `extends`. + +Если конфигурация содержит поле `extends`, библиотека сначала применяет указанные в нём конфигурации по порядку. Параметры каждой родительской конфигурации применяются по очереди: последняя в списке переопределяет предыдущие. + +После этого применяются параметры самой выбранной конфигурации, которые переопределяют всё, что было задано раньше. +Если конфигурация не содержит `extends`, она полностью изолирована: применяются только её собственные параметры. - "queues": 1, - "verbosity": 2, +### Пример конфигурационного файла + +``` json +{ + "gpu0": { + "backend": "by_index", + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": false + }, + + "debug": { + "profiling": true, // будет переопределен конфигурацией "gpu0" + "allocator_type": "general", + "verbosity": 3 + }, + + "debug_gpu0": { + "extends": ["debug", "gpu0"] + } + } ``` +### Запуск +```bash +SPLA_CONFIG=debug_gpu0 ./program +``` +Или через CLI: +```bash +./program --spla-config=debug_gpu0 +``` -## Наследование профилей +### Итоговый набор параметров + +| Параметр | Значение | Источник | +| :--- | :--- | :--- | +| backend | `by_index` | конфигурация `gpu0` | +| platform_index | `0` | конфигурация `gpu0` | +| device_index | `0` | конфигурация `gpu0` | +| if_gpu_unavailable | `"abort"` | конфигурация `gpu0` | +| queues_count | `1` | конфигурация `gpu0` | +| profiling | `false` | конфигурация `gpu0` | +| allocator_type | `general` | конфигурация `debug` | +| verbosity | `3` | конфигурация `debug` | +--- -Иногда профили пересекаются по смыслу - например, **debug_gpu1** должен включать и режим отладки, и выбор GPU 1. Чтобы не дублировать параметры, профиль может наследовать другие профили через поле `extends`. -- Если профиль содержит поле `extends`, библиотека сначала применяет указанные в нём профили по порядку. -- Затем к базовым параметрам применяются параметры каждого родительского профиля по очереди: последний в списке переопределяет предыдущие. -- После этого применяются параметры самого выбранного профиля, которые переопределяют всё, что было задано раньше. +`configs` - словарь именованных конфигураций. Конфигурации из разных файлов (по умолчанию, системного, пользовательского) сливаются по именам: одноимённые конфигурации объединяются по параметрам, а уникальные добавляются. Итоговый набор используется для разрешения `extends` и выбора активной конфигурации. -### Пример +Имена в `extends` берутся из всех конфигураций, определённых в конфигурационгом файле по умолчанию, системном и пользовательском файлах конфигурации. Это позволяет наследовать конфигурации, определённые на другом уровне. Например, пользовательская конфигурация может наследовать `"default"` из заводского файла, не дублируя его параметры. +### Пример конфигурационного файла +Конфигурационный файл по умолчанию: ``` json { - "execution": { "device": 0 }, - "verbosity": 2, + "current_config": "default", - "profiles": { - "gpu0": { "execution": { "device": 0 } }, - "gpu1": { "execution": { "device": 1 } }, - "gpu2": { "execution": { "device": 2 } }, + "configs": { + "default": { + "backend": "gpu", // переопределен + "if_gpu_unavailable": "use_cpu", // переопределен - "debug": { "verbosity": 3, "profiling": true }, - "bench": { "verbosity": 0 }, + "queues_count": 1, + "profiling": false, // переопределен + "allocator_type": "general", - "debug_gpu1": { - "extends": ["debug", "gpu1"] - }, - "bench_gpu2": { - "extends": ["bench", "gpu2"] + "verbosity": 2 } } } ``` -### Запуск -```bash -SPLA_PROFILE=debug_gpu1 ./program -SPLA_PROFILE=bench_gpu2 ./program -``` -Или через CLI: -```bash -./program --spla-profile=debug_gpu1 -``` - -### Итоговый конфигурационный файл +Конфигурационный файл, созданный пользователем: ```json { - "execution": { "device": 1 }, - "verbosity": 3, - "profiling": true + "current_config": "gpu0", + + "configs": { + "gpu0": { + "extends": ["default"], + "backend": "by_index", // переопределяет "backend": "gpu" + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", // переопределяет "if_gpu_unavailable": "use_cpu" + "queues_count": 1, + "profiling": true + } + } } ``` +### Итоговый набор параметров + +| Параметр | Значение | Источник | +| :--- | :--- | :--- | +| backend | `by_index` | конфигурация `gpu0` | +| platform_index | `0` | конфигурация `gpu0` | +| device_index | `0` | конфигурация `gpu0` | +| if_gpu_unavailable | `"abort"` | конфигурация `gpu0` | +| queues_count | `1` | конфигурация `gpu0` | +| profiling | `true` | конфигурация `gpu0` | +| allocator_type | `general` | конфигурация по умолчанию | +| verbosity | `2` | конфигурация по умолчанию | + --- --- @@ -229,54 +301,87 @@ SPLA_PROFILE=bench_gpu2 ./program Тип устройства задаётся параметром backend ```json -{ "backend": "gpu" } //Использовать первое доступное GPU - -{ "backend": "cpu" } //Использовать CPU - -{ "backend": "any" } //Использовать первое доступное устройство любого типа +{ + "configs": { + "gpu_only": { "backend": "gpu" }, // "gpu" - использовать первое доступное GPU; + "cpu_only": { "backend": "cpu" }, // "cpu" - использовать CPU; + "any": { "backend": "any" } // "any" - использовать первое доступное устройство любого типа. + } +} ``` -Индексы `platform_index` и `device_index` при этих значениях игнорируются. Это позволяет запускать программу на GPU или CPU без знания индексов. +Индексы `platform_index` и `device_index` при этих значениях игнорируются. ### Поведение при отсутствии GPU -Если выбран backend: "gpu", но GPU недоступен, поведение определяется параметром `if_gpu_unavailable`: +Если выбран backend: `"gpu"`, но GPU недоступен, поведение определяется параметром `if_gpu_unavailable`: ```json { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu" //Библиотека переключается на CPU и продолжает работу -} - -{ - "backend": "gpu", - "if_gpu_unavailable": "abort" //Библиотека возвращает ошибку и не продолжает работу - //Стоит использовать, если требуется гарантировать выполнение на GPU + "configs": { + "gpu_or_cpu": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu" + }, + "gpu_only": { + "backend": "gpu", + "if_gpu_unavailable": "abort" + } + } } ``` -`if_gpu_unavailable` применяется только при backend: "gpu" и backend: "any". При backend: "cpu" параметр игнорируется. +`"use_cpu"` - библиотека переключается на CPU и продолжает работу. \ +`"abort"` - библиотека возвращает ошибку и не продолжает работу. \ +`if_gpu_unavailable` применяется только при backend: `"by_index"`, backend: `"gpu"` и backend: `"any"`. При backend: `"cpu"` параметр игнорируется. ## Многократный запуск на разных устройствах с разными параметрами -Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо того чтобы держать несколько конфигурационных файлов, вы описываете всё в одном. - -Подробнее в главе про [профили](#профили) и [наследование профилей (`extends`)](#наследование-профилей). - +Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо того чтобы держать несколько файлов конфигурации, вы описываете всё в одном. ```json { - "execution": { "device": 0 }, - "verbosity": 2, - - "profiles": { - "gpu0": { "execution": { "device": 0 } }, - "gpu1": { "execution": { "device": 1 } }, - "gpu2": { "execution": { "device": 2 } }, - - "debug": { "verbosity": 3, "profiling": true }, - "bench": { "verbosity": 0 }, + "current_config": "default", + + "configs": { + "default": { "backend": "gpu", "verbosity": 2 }, + + "gpu0": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 0 + }, + "gpu1": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 1 + }, + "gpu2": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 2 + }, + + "debug": { + "extends": ["default"], + "verbosity": 3, + "profiling": true + }, + "bench": { + "extends": ["default"], + "verbosity": 0 + s}, "debug_gpu1": { "extends": ["debug", "gpu1"] }, "bench_gpu2": { "extends": ["bench", "gpu2"] } } } -``` \ No newline at end of file +``` +Запуск +```bash +SPLA_CONFIG=gpu1 ./program +SPLA_CONFIG=debug ./program +SPLA_CONFIG=debug_gpu1 ./program +``` +Подробнее в главе про [конфигурации](#конфигурации) и [наследование конфигураций (`extends`)](#наследование-конфигураций). From 73a39f687c3bf9dfccd94768b10b9064684ecc70 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 6 Oct 2026 21:25:09 +0300 Subject: [PATCH 47/57] removed "configs" and "current_config" --- src/opencl/UserGuide.md | 380 ++++++++++++++++++++++------------------ 1 file changed, 206 insertions(+), 174 deletions(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 40d0a9470..7528cf081 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -42,44 +42,12 @@ $ spla --softcheck ``` ## Конфигурационный файл -Файл конфигурации `spla_conf.json` состоит из двух частей: - -- `current_config` - имя конфигурации, которую вы хотите применить; - -- `configs` - словарь именованных конфигураций. - -Каждая конфигурация - это именованный набор параметров библиотеки. Все параметры библиотеки описываются внутри конфигураций. - -Файл конфигурации, предоставляющийся библиотекой, имеет следующую структуру: -```json -{ - "current_config": "default", - - "configs": { - "default": { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu", - - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - - "verbosity": 2 - } - } -} -``` - -### Параметры верхнего уровня -| Параметр | Тип | Описание | Допустимые значения | -| :--- | :--- | :--- | :--- | -| current_config | string | Имя применяемой конфигурации | имя из `configs` (со всех уровней) | -| configs | object | Словарь именованных конфигураций | { "name": { ... } } | +Конфигурационные файлы состоят из набора конфигураций, каждая конфигурация - это именованный набор параметров библиотеки, все параметры библиотеки описываются внутри конфигураций. ### Параметры конфигурации | Параметр | Тип | Описание | Допустимые значения | | :--- | :--- | :--- | :--- | -| extends | array of string | Список конфигураций-родителей | имена из `configs` (со всех уровней) | +| extends | array of string | Список конфигураций-родителей | имена конфигураций (со всех уровней) | | backend | string | На каком устройстве работать | `"gpu"` - только GPU
`"cpu"` - только CPU
`"any"` - любое доступное устройство
`"by_index"` - выбрать по индексам ниже | | platform_index | int | Индекс OpenCL платформы
Используются только при backend: `"by_index"`
При других значениях backend - игнорируются | ≥ 0 | | device_index | int | Индекс устройства внутри платформы
Используются только при backend: `"by_index"`
При других значениях backend - игнорируются | ≥ 0 | @@ -90,21 +58,38 @@ $ spla --softcheck | linear_alloc_size | int | Размер линейного аллокатора (байт)
Используются только при allocator_type: `"linear"` | ≥ 0 | | verbosity | int | Уровень логирования | `0` - нет вывода,
`1` - только ошибки,
`2` - ошибки, предупреждения,
`3` - ошибки, предупреждения, дополнительная информация | +Файл конфигурации, предоставляющийся библиотекой, имеет следующую структуру: +```json +{ + "default": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", + + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + + "verbosity": 2 + } +} +``` ## Настройка Если параметры по умолчанию вас не устраивают, вы можете настроить библиотеку. Способы конфигурирования перечислены в порядке убывания приоритета: 1. Аргументы командной строки. 2. Переменные окружения. -3. Пользовательский конфигурационный файл. -4. Системный конфигурационный файл. -5. Конфигурационный файл, поставляющийся библиотекой. +3. Файл, путь к которому пользователь может задать явно. +- > При необходимости пользователь может явно указать файл с конфигурациями, который не находится по пути пользовательского и системного конфигурационного файла. +4. Пользовательский конфигурационный файл. +5. Системный конфигурационный файл. +6. Конфигурационный файл, поставляющийся библиотекой. ### Расположение конфигурационных файлов **Конфигурационный файл с параметрами по умолчанию:** -Файл конфигурации с параметрами по умолчанию поставляется вместе с пакетом pyspla и располагается внутри директории установленного Python-пакета. +>Файл конфигурации с параметрами по умолчанию поставляется вместе с пакетом pyspla и располагается внутри директории установленного Python-пакета. Расположение зависит от способа установки пакета (глобально, --user, в виртуальном окружении). **Системный конфигурационный файл:** @@ -117,43 +102,48 @@ Windows: `%ProgramData%\spla\spla_conf.json` macOS: `~/Library/Application Support/spla/spla_conf.json` \ Windows: `%APPDATA%\spla\spla_conf.json` +**Пользовательский конфигурационный файл, задавающийся явно:** + +>На усмотрение пользователя. + ## Конфигурации -Конфигурации позволяют хранить несколько наборов настроек в одном файле конфигурации и переключаться между ними при запуске. Это удобно, когда одну и ту же программу нужно запускать в разных режимах. +Конфигурации позволяют хранить несколько наборов настроек в одном конфигурационном файле и переключаться между ними при запуске. Это удобно, когда одну и ту же программу нужно запускать в разных режимах. + +Если пользователь не укажет конфигурацию, то будет взята конфигурация `"default"` из файла, который идет с библиотекой. ### Пример конфигурационного файла ```json { - "configs": { - - "cpu": { - "backend": "cpu", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "verbosity": 2 - }, - "gpu0": { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu", - "queues_count": 2, - "profiling": true, - "allocator_type": "linear", - "linear_alloc_size": 8, - "verbosity": 0 - }, - "gpu1": { - "backend": "by_index", - "platform_index": 0, - "device_index": 2, - "if_gpu_unavailable": "abort", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "verbosity": 3 - } - } + "cpu": { + "backend": "cpu", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 2 + }, + + "gpu0": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", + "queues_count": 2, + "profiling": true, + "allocator_type": "linear", + "linear_alloc_size": 8, + "verbosity": 0 + }, + + "gpu1": { + "backend": "by_index", + "platform_index": 0, + "device_index": 2, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 3 + } } ``` ### Запуск @@ -175,40 +165,30 @@ SPLA_CONFIG=gpu1 ./program После этого применяются параметры самой выбранной конфигурации, которые переопределяют всё, что было задано раньше. Если конфигурация не содержит `extends`, она полностью изолирована: применяются только её собственные параметры. -### Пример конфигурационного файла +### Примеры конфигурационных файлов ``` json { - "gpu0": { - "backend": "by_index", - "platform_index": 0, - "device_index": 0, - "if_gpu_unavailable": "abort", - "queues_count": 1, - "profiling": false - }, - - "debug": { - "profiling": true, // будет переопределен конфигурацией "gpu0" - "allocator_type": "general", - "verbosity": 3 - }, - - "debug_gpu0": { - "extends": ["debug", "gpu0"] + "gpu0": { + "backend": "by_index", + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": false + }, + + "debug": { + "profiling": true, // будет переопределен конфигурацией "gpu0" + "allocator_type": "general", + "verbosity": 3 + }, + + "debug_gpu0": { + "extends": ["debug", "gpu0"] } - } ``` -### Запуск -```bash -SPLA_CONFIG=debug_gpu0 ./program -``` -Или через CLI: -```bash -./program --spla-config=debug_gpu0 -``` - ### Итоговый набор параметров | Параметр | Значение | Источник | @@ -221,49 +201,74 @@ SPLA_CONFIG=debug_gpu0 ./program | profiling | `false` | конфигурация `gpu0` | | allocator_type | `general` | конфигурация `debug` | | verbosity | `3` | конфигурация `debug` | +### Запуск +```bash +SPLA_CONFIG=debug_gpu0 ./program +``` +Или через CLI: +```bash +./program --spla-config=debug_gpu0 +``` --- +```json +{ + "gpu0": { + "backend": "by_index", + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 3 + }, + "gpu0_profiling_true": { + "extends": ["gpu0"], + "profiling": true // переопределит "profiling": false конфигурации "gpu0" + } +} +``` +### Запуск +```bash +SPLA_CONFIG=gpu0_profiling_true ./program +``` +Или через CLI: +```bash +./program --spla-config=gpu0_profiling_true +``` +Конфигурационные файлы состоят из списка именованных конфигураций. Конфигурации из разных файлов (по умолчанию, системного, пользовательского, пользовательского с явно указанным путем) сливаются по именам: одноимённые конфигурации объединяются по параметрам, а уникальные добавляются. Итоговый набор используется для разрешения `extends` и выбора активной конфигурации. -`configs` - словарь именованных конфигураций. Конфигурации из разных файлов (по умолчанию, системного, пользовательского) сливаются по именам: одноимённые конфигурации объединяются по параметрам, а уникальные добавляются. Итоговый набор используется для разрешения `extends` и выбора активной конфигурации. - -Имена в `extends` берутся из всех конфигураций, определённых в конфигурационгом файле по умолчанию, системном и пользовательском файлах конфигурации. Это позволяет наследовать конфигурации, определённые на другом уровне. Например, пользовательская конфигурация может наследовать `"default"` из заводского файла, не дублируя его параметры. +Имена в `extends` берутся из всех конфигураций, определённых в конфигурационгом файле по умолчанию, системном, пользовательском и пользовательском с явно указанным путем файлах конфигурации. Это позволяет наследовать конфигурации, определённые на другом уровне. Например, пользовательская конфигурация может наследовать `"default"` из файла по умолчанию, не дублируя его параметры. ### Пример конфигурационного файла Конфигурационный файл по умолчанию: ``` json { - "current_config": "default", + "default": { + "backend": "gpu", // переопределится на "by_index" + "if_gpu_unavailable": "use_cpu", // переопределится на "abort" - "configs": { - "default": { - "backend": "gpu", // переопределен - "if_gpu_unavailable": "use_cpu", // переопределен + "queues_count": 1, + "profiling": false, // переопределится на true + "allocator_type": "general", - "queues_count": 1, - "profiling": false, // переопределен - "allocator_type": "general", - - "verbosity": 2 + "verbosity": 2 } - } } ``` Конфигурационный файл, созданный пользователем: ```json { - "current_config": "gpu0", - - "configs": { - "gpu0": { - "extends": ["default"], - "backend": "by_index", // переопределяет "backend": "gpu" - "platform_index": 0, - "device_index": 0, - "if_gpu_unavailable": "abort", // переопределяет "if_gpu_unavailable": "use_cpu" - "queues_count": 1, - "profiling": true - } - } + "gpu0": { + "extends": ["default"], + "backend": "by_index", // переопределяет "backend": "gpu" + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", // переопределяет "if_gpu_unavailable": "use_cpu" + "queues_count": 1, + "profiling": true + } } ``` @@ -287,6 +292,7 @@ SPLA_CONFIG=debug_gpu0 ./program 1. Быстрый запуск без настройки. 2. Выбор между CPU и GPU без указания индексов. 3. Многократный запуск на разных устройствах с разными параметрами. + 4. Запуск с конфигурациями из произвольного файла. ## Быстрый запуск без настройки @@ -302,11 +308,9 @@ SPLA_CONFIG=debug_gpu0 ./program Тип устройства задаётся параметром backend ```json { - "configs": { - "gpu_only": { "backend": "gpu" }, // "gpu" - использовать первое доступное GPU; - "cpu_only": { "backend": "cpu" }, // "cpu" - использовать CPU; - "any": { "backend": "any" } // "any" - использовать первое доступное устройство любого типа. - } + "gpu_only": { "backend": "gpu" }, // "gpu" - использовать первое доступное GPU; + "cpu_only": { "backend": "cpu" }, // "cpu" - использовать CPU; + "any": { "backend": "any" } // "any" - использовать первое доступное устройство любого типа. } ``` @@ -318,15 +322,13 @@ SPLA_CONFIG=debug_gpu0 ./program ```json { - "configs": { - "gpu_or_cpu": { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu" - }, - "gpu_only": { - "backend": "gpu", - "if_gpu_unavailable": "abort" - } + "gpu_or_cpu": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu" + }, + "gpu_only": { + "backend": "gpu", + "if_gpu_unavailable": "abort" } } ``` @@ -339,43 +341,39 @@ SPLA_CONFIG=debug_gpu0 ./program Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо того чтобы держать несколько файлов конфигурации, вы описываете всё в одном. ```json { - "current_config": "default", - - "configs": { - "default": { "backend": "gpu", "verbosity": 2 }, - - "gpu0": { - "extends": ["default"], - "backend": "by_index", - "platform_index": 0, - "device_index": 0 - }, - "gpu1": { - "extends": ["default"], - "backend": "by_index", - "platform_index": 0, - "device_index": 1 - }, - "gpu2": { - "extends": ["default"], - "backend": "by_index", - "platform_index": 0, - "device_index": 2 - }, - - "debug": { - "extends": ["default"], - "verbosity": 3, - "profiling": true - }, - "bench": { - "extends": ["default"], - "verbosity": 0 - s}, - - "debug_gpu1": { "extends": ["debug", "gpu1"] }, - "bench_gpu2": { "extends": ["bench", "gpu2"] } - } + "default": { "backend": "gpu", "verbosity": 2 }, + + "gpu0": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 0 + }, + "gpu1": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 1 + }, + "gpu2": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 2 + }, + + "debug": { + "extends": ["default"], + "verbosity": 3, + "profiling": true + }, + "bench": { + "extends": ["default"], + "verbosity": 0 + }, + + "debug_gpu1": { "extends": ["debug", "gpu1"] }, + "bench_gpu2": { "extends": ["bench", "gpu2"] } } ``` Запуск @@ -385,3 +383,37 @@ SPLA_CONFIG=debug ./program SPLA_CONFIG=debug_gpu1 ./program ``` Подробнее в главе про [конфигурации](#конфигурации) и [наследование конфигураций (`extends`)](#наследование-конфигураций). + +## Запуск с конфигурациями из произвольного файла + +Вам нужно запустить тесты в CI с отдельным файлом конфигурации. + +В среде CI неудобно и нежелательно трогать системный и пользовательский файлы конфигурации, так как они могут влиять на другие задачи. Вместо этого пользователь может описать конфигурации в отдельном файле внутри репозитория и указать путь к нему при запуске. + +Файл может содержать конфигурации, рассчитанные именно на тестовую среду: например, ограниченное число очередей, отключённое профилирование, фиксированный уровень логирования. + +```json +{ + "test_gpu0": { + "backend": "by_index", + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 1 + }, + "test_gpu1": { + "backend": "by_index", + "platform_index": 0, + "device_index": 1, + "if_gpu_unavailable": "abort", + "queues_count": 2, + "profiling": false, + "allocator_type": "linear", + "linear_alloc_size": 8, + "verbosity": 0 + } +} +``` \ No newline at end of file From 103f80e8c100d4d7fa36105e2f296433ae261688 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 7 Oct 2026 16:21:14 +0300 Subject: [PATCH 48/57] added about how to run with user conf --- src/opencl/UserGuide.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 7528cf081..4de350200 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -416,4 +416,25 @@ SPLA_CONFIG=debug_gpu1 ./program "verbosity": 0 } } -``` \ No newline at end of file +``` + +### Запуск +```bash +SPLA_CONFIG_FILE=./path/to/conf/spla_conf.json SPLA_CONFIG=test_gpu1 ./program +``` +Или через CLI: +```bash +./program --spla-config-file=./path/to/conf/spla_conf.json --spla-config=test_gpu1 +``` +Будет применена конфигурация `test_gpu1` из файла `./path/to/conf/spla_conf.json`. + +Если указан файл, но не указана конфигурация, то будет применена первая конфигурация из файла. + +```bash +SPLA_CONFIG_FILE=./path/to/conf/spla_conf.json ./program +``` +Или через CLI: +```bash +./program --spla-config-file=./path/to/conf/spla_conf.json +``` +В этом случае применяется конфигурация `test_gpu0`. \ No newline at end of file From 4f9309fe020d6323a84d0af80ceb9e07af2b5b6a Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 7 Oct 2026 19:17:35 +0300 Subject: [PATCH 49/57] fixed ci scenar --- src/opencl/UserGuide.md | 91 ++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 4de350200..1e5ecfacb 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -388,25 +388,41 @@ SPLA_CONFIG=debug_gpu1 ./program Вам нужно запустить тесты в CI с отдельным файлом конфигурации. -В среде CI неудобно и нежелательно трогать системный и пользовательский файлы конфигурации, так как они могут влиять на другие задачи. Вместо этого пользователь может описать конфигурации в отдельном файле внутри репозитория и указать путь к нему при запуске. +В среде CI неудобно и нежелательно трогать системный и пользовательский файлы конфигурации, а конфигурация тестов должна лежать в репозитории. Поэтому конфигурации описывают в отдельном файле внутри репозитория и указывают путь к нему при запуске и имя конфигурации. -Файл может содержать конфигурации, рассчитанные именно на тестовую среду: например, ограниченное число очередей, отключённое профилирование, фиксированный уровень логирования. +``` +my_project/ +├── .github/ +│ └── workflows/ +│ ├── ci_with_conf.yml +│ └── ci_spla_conf.json +├── src/ +└── tests/ +``` +### ci_spla_conf.json ```json { + "test_cpu": { + "backend": "cpu", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 1 + }, "test_gpu0": { - "backend": "by_index", - "platform_index": 0, + "backend": "by_index", + "platform_index": 0, "device_index": 0, "if_gpu_unavailable": "abort", - "queues_count": 1, + "queues_count": 2, "profiling": false, "allocator_type": "general", - "verbosity": 1 - }, + "verbosity": 0 + }, "test_gpu1": { - "backend": "by_index", - "platform_index": 0, + "backend": "by_index", + "platform_index": 0, "device_index": 1, "if_gpu_unavailable": "abort", "queues_count": 2, @@ -414,27 +430,44 @@ SPLA_CONFIG=debug_gpu1 ./program "allocator_type": "linear", "linear_alloc_size": 8, "verbosity": 0 - } + } } ``` -### Запуск -```bash -SPLA_CONFIG_FILE=./path/to/conf/spla_conf.json SPLA_CONFIG=test_gpu1 ./program -``` -Или через CLI: -```bash -./program --spla-config-file=./path/to/conf/spla_conf.json --spla-config=test_gpu1 -``` -Будет применена конфигурация `test_gpu1` из файла `./path/to/conf/spla_conf.json`. - -Если указан файл, но не указана конфигурация, то будет применена первая конфигурация из файла. - -```bash -SPLA_CONFIG_FILE=./path/to/conf/spla_conf.json ./program -``` -Или через CLI: -```bash -./program --spla-config-file=./path/to/conf/spla_conf.json +### ci_with_conf.yml +```yml +name: CI + +on: [push, pull_request] + +jobs: + test: + name: Test (${{ matrix.config }}) + runs-on: [self-hosted] + + strategy: + fail-fast: false + matrix: + config: [test_cpu, test_gpu0, test_gpu1] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyspla pytest + + - name: Run tests + env: + SPLA_CONFIG_FILE: ${{ github.workspace }}/.github/workflows/ci_spla_conf.json + SPLA_CONFIG: ${{ matrix.config }} + run: pytest tests/ ``` -В этом случае применяется конфигурация `test_gpu0`. \ No newline at end of file +Если пользователь не укажет конфигурацию, то будет взята конфигурация `"default"` из файла, который идет с библиотекой. \ No newline at end of file From e6a8c45525b392616604a2d54e773c4181faa32e Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Wed, 7 Oct 2026 19:32:21 +0300 Subject: [PATCH 50/57] =?UTF-8?q?=D0=97=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20?= =?UTF-8?q?=D1=81=20->=20=D0=97=D0=B0=D0=BF=D1=83=D1=81=D0=BA=20ci=20?= =?UTF-8?q?=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/opencl/UserGuide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md index 1e5ecfacb..fa774e23e 100644 --- a/src/opencl/UserGuide.md +++ b/src/opencl/UserGuide.md @@ -384,7 +384,7 @@ SPLA_CONFIG=debug_gpu1 ./program ``` Подробнее в главе про [конфигурации](#конфигурации) и [наследование конфигураций (`extends`)](#наследование-конфигураций). -## Запуск с конфигурациями из произвольного файла +## Запуск ci с конфигурациями из произвольного файла Вам нужно запустить тесты в CI с отдельным файлом конфигурации. From 0dc7fba9aeb18f6771c599d3add1c7e67b713834 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 09:12:34 +0300 Subject: [PATCH 51/57] added new configuration func --- CMakeLists.txt | 37 +- build.py | 2 + {src/opencl => docs}/LibsCompare.md | 7 +- docs/UserGuide.md | 261 +++++++++++++ docs/UserManual.md | 305 +++++++++++++++ include/spla.h | 1 + python/pyspla/bridge.py | 38 ++ python/pyspla/spla_conf.json | 12 + python/setup.py | 2 +- src/binding/c_config.hpp | 5 + src/binding/c_library.cpp | 15 +- src/core/cl_config_status.hpp | 48 +++ src/core/configure.cpp | 578 ++++++++++++++++++++++++++++ src/core/configure.hpp | 106 +++++ src/opencl/UserGuide.md | 473 ----------------------- src/opencl/UserManual.md | 239 ------------ src/opencl/cl_accelerator.cpp | 131 +++++-- src/opencl/cl_accelerator.hpp | 7 +- tools/soft_check.cpp | 154 ++++++++ 19 files changed, 1650 insertions(+), 771 deletions(-) rename {src/opencl => docs}/LibsCompare.md (93%) create mode 100644 docs/UserGuide.md create mode 100644 docs/UserManual.md create mode 100644 python/pyspla/spla_conf.json create mode 100644 src/core/cl_config_status.hpp create mode 100644 src/core/configure.cpp create mode 100644 src/core/configure.hpp delete mode 100644 src/opencl/UserGuide.md delete mode 100644 src/opencl/UserManual.md create mode 100644 tools/soft_check.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ef13ccc2..ee186967d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,22 @@ cmake_minimum_required(VERSION 3.15 FATAL_ERROR) project(spla LANGUAGES CXX) +###################################################################### +## Package version +## python/VERSION.md is the single source of truth for the version: +## python/setup.py reads it for the PyPI package and the C++ library +## gets it as the SPLA_VERSION compile definition. + +file(READ "${CMAKE_CURRENT_LIST_DIR}/python/VERSION.md" SPLA_VERSION_RAW) +string(STRIP "${SPLA_VERSION_RAW}" SPLA_VERSION) +message(STATUS "SPLA package version: ${SPLA_VERSION}") + ###################################################################### ## public options option(SPLA_BUILD_TESTS "Build test folder with modules tests" YES) option(SPLA_BUILD_EXAMPLES "Build library example applications with algorithms" YES) +option(SPLA_BUILD_TOOLS "Build command line tools (spla)" YES) option(SPLA_BUILD_OPENCL "Build library with opencl backend" YES) ###################################################################### @@ -257,9 +268,6 @@ set(SRC_OPENCL) if (SPLA_BUILD_OPENCL) set(SRC_OPENCL - src/opencl/cl_config_status.hpp - src/opencl/cl_configure.cpp - src/opencl/cl_configure.hpp src/opencl/cl_debug.hpp src/opencl/cl_accelerator.cpp src/opencl/cl_accelerator.hpp @@ -322,6 +330,9 @@ add_library(spla SHARED include/spla/vector.hpp src/core/accelerator.hpp src/core/common.hpp + src/core/cl_config_status.hpp + src/core/configure.cpp + src/core/configure.hpp src/core/dispatcher.cpp src/core/dispatcher.hpp src/core/logger.cpp @@ -393,11 +404,13 @@ target_include_directories(spla PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src) set_target_properties(spla PROPERTIES OUTPUT_NAME "spla_${SPLA_ARCH}") target_compile_definitions(spla PRIVATE SPLA_EXPORTS) +target_compile_definitions(spla PRIVATE SPLA_VERSION="${SPLA_VERSION}") target_link_libraries(spla PRIVATE robin_hood) target_link_libraries(spla PRIVATE svector) target_link_libraries(spla PRIVATE CLI11::CLI11) target_link_libraries(spla PRIVATE nlohmann_json::nlohmann_json) +target_link_libraries(spla PRIVATE ${CMAKE_DL_LIBS}) if (SPLA_BUILD_OPENCL) target_link_libraries(spla PUBLIC OpenCL) @@ -413,6 +426,13 @@ spla_target_compile_definitions(spla) spla_target_compile_options(spla) spla_target_link_options(spla) +set(SPLA_CONF_SRC "${CMAKE_CURRENT_LIST_DIR}/python/pyspla/spla_conf.json") +set(SPLA_CONF_DST "${CMAKE_BINARY_DIR}/spla_conf.json") +add_custom_command(TARGET spla POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${SPLA_CONF_SRC}" "${SPLA_CONF_DST}" + COMMENT "Copying shipped configuration file spla_conf.json next to the library") + ###################################################################### ## Add examples directory @@ -434,6 +454,17 @@ if (SPLA_BUILD_EXAMPLES) spla_example_application(convert) endif () +###################################################################### +## Add command line tools + +if (SPLA_BUILD_TOOLS) + message(STATUS "Add command line tools to build") + + add_executable(spla_cli tools/soft_check.cpp) + target_link_libraries(spla_cli PRIVATE spla) + set_target_properties(spla_cli PROPERTIES OUTPUT_NAME spla) +endif () + ###################################################################### ## Add unit-tests directory diff --git a/build.py b/build.py index 95cdeb90f..bbf548da3 100644 --- a/build.py +++ b/build.py @@ -35,6 +35,7 @@ def main(): parser.add_argument("--build-type", default="Release", help="type of build: `Debug`, `Release` or `RelWithDebInfo`") parser.add_argument("--tests", default="YES", help="build tests") parser.add_argument("--examples", default="YES", help="build example applications") + parser.add_argument("--tools", default="YES", help="build command line tools") parser.add_argument("--opencl", default="YES", help="build opencl acceleration backend") parser.add_argument("--target", default="all", help="which target to build") parser.add_argument("--nt", default="4", help="number of os threads for build") @@ -44,6 +45,7 @@ def main(): build_config_args = ["cmake", ".", "-B", args.build_dir, "-G", "Ninja", f"-DCMAKE_BUILD_TYPE={args.build_type}", f"-DSPLA_BUILD_TESTS={args.tests}", f"-DSPLA_BUILD_EXAMPLES={args.examples}", + f"-DSPLA_BUILD_TOOLS={args.tools}", f"-DSPLA_BUILD_OPENCL={args.opencl}"] if args.arch: diff --git a/src/opencl/LibsCompare.md b/docs/LibsCompare.md similarity index 93% rename from src/opencl/LibsCompare.md rename to docs/LibsCompare.md index 14f5ce656..3001d1ae7 100644 --- a/src/opencl/LibsCompare.md +++ b/docs/LibsCompare.md @@ -9,7 +9,7 @@ | **Источники** | CLI (argv) / env / файлы | +/-, форматы | | **Стандарт C++** | минимальная версия | C++хх | | **Поддерживает стандарт иерархии** | Linux/Windows/MacOS | +/- | -| **Способ распространения** | header-only / статическая / динамическая | — | +| **Способ распространения** | header-only / статическая / динамическая | - | | **ОС** | Linux / Windows / macOS | +/-, компиляторы | | **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | | **Issues** | open, closed/open | n, коэффициент | @@ -119,8 +119,3 @@ ### Итог: По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. - - -# Механизм конфигурирования библиотеки SPLA - -Механизм конфигурирования описывается в разделах: [Мануал пользователя](#UserManual) и [Руководство пользователя](#UserGuide) \ No newline at end of file diff --git a/docs/UserGuide.md b/docs/UserGuide.md new file mode 100644 index 000000000..27a1fc101 --- /dev/null +++ b/docs/UserGuide.md @@ -0,0 +1,261 @@ +# User Guide + +Руководство пользователя библиотеки spla. Содержит сценарии использования механизма конфигурирования: от быстрого запуска без настройки до запуска тестов в CI. Полный справочник всех параметров, флагов и переменных окружения приведён в [User Manual](UserManual.md). + +## Содержание + +1. [Проверка окружения](#проверка-окружения) +2. [Сценарий 1. Быстрый запуск без настройки](#сценарий-1-быстрый-запуск-без-настройки) +3. [Сценарий 2. Выбор между CPU и GPU без указания индексов](#сценарий-2-выбор-между-cpu-и-gpu-без-указания-индексов) +4. [Сценарий 3. Несколько устройств и режимов в одном файле](#сценарий-3-несколько-устройств-и-режимов-в-одном-файле) +5. [Сценарий 4. Запуск в CI с файлом из репозитория](#сценарий-4-запуск-в-ci-с-файлом-из-репозитория) +6. [Приоритет источников конфигурации](#приоритет-источников-конфигурации) +7. [Где лежат файлы конфигурации](#где-лежат-файлы-конфигурации) + +## Проверка окружения + +После установки выполните команду, которая подтверждает, что библиотека готова к использованию: + +```bash +spla --softcheck +``` + +Команда: + +1. Читает конфигурационный файл, поставляемый библиотекой. +2. Инициализирует OpenCL, выбирает платформу и устройство. +3. Запускает простое тестовое задание `2 + 3`. +4. Сообщает статус. + +Пример успешного вывода: + +```bash +$ spla --softcheck +[spla:check] Starting sanity check... +[spla:check] Initializing OpenCL... +[spla:check] Selected accelerator: OpenCL NVIDIA CUDA | device: NVIDIA GeForce RTX 3070 Laptop GPU | vendor: nvidia | mcu: 40 | wave: 32 | mwgs: 1024 +[spla:check] Running test task: 2 + 3 = ... +[spla:check] Result: 5 (expected 5) +[spla:check] SUCCESS - spla works correctly +``` + +## Сценарий 1. Быстрый запуск без настройки + +Вы хотите получить работоспособное приложение без настройки - ничего настраивать не нужно. Библиотека использует параметры по умолчанию из конфигурационного файла, поставляемого вместе с библиотекой. + +```bash +./program +``` + +Сценарий работает одинаково на Linux, macOS и Windows. Если GPU недоступен, библиотека по умолчанию автоматически переключится на CPU (параметр `if_gpu_unavailable: "use_cpu"`), сообщив об этом. + +Перед первым запуском рекомендуется выполнить [`spla --softcheck`](#проверка-окружения), чтобы убедиться, что всё необходимое для работы spla установлено. + +## Сценарий 2. Выбор между CPU и GPU без указания индексов + +Вы хотите управлять типом устройства, но не указывать конкретные индексы OpenCL-платформ и устройств. + +Тип устройства задаётся параметром `backend` в конфигурационном файле: + +```json +{ + "gpu_only": { "backend": "gpu" }, + "cpu_only": { "backend": "cpu" }, + "any": { "backend": "any" } +} +``` + +- `"gpu"` - использовать первое доступное GPU, +- `"cpu"` - использовать CPU, +- `"any"` - использовать первое доступное устройство любого типа. + +Индексы `platform_index` и `device_index` при этих значениях игнорируются. + +### Поведение при отсутствии GPU + +Если выбран `backend: "gpu"`, но GPU недоступен, поведение определяется параметром `if_gpu_unavailable`: + +```json +{ + "gpu_or_cpu": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu" + }, + "gpu_only": { + "backend": "gpu", + "if_gpu_unavailable": "abort" + } +} +``` + +- `"use_cpu"` - библиотека переключается на CPU и продолжает работу, +- `"abort"` - + библиотека возвращает ошибку и не продолжает работу. + +Запуск нужной конфигурации: + +```bash +./program --spla-config=gpu_or_cpu +./program --spla-config=gpu_only +``` + +`if_gpu_unavailable` применяется при `backend: "gpu"`, `"any"` и `"by_index"`. При `backend: "cpu"` параметр игнорируется. + +## Сценарий 3. Несколько устройств и режимов в одном файле + +Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо нескольких файлов конфигурации вы описываете всё в одном. + +```json +{ + "default": { "backend": "gpu", "verbosity": 2 }, + + "gpu0": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 0 + }, + "gpu1": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 1 + }, + + "debug": { + "extends": ["default"], + "verbosity": 3, + "profiling": true + }, + "bench": { + "extends": ["default"], + "verbosity": 0 + }, + + "debug_gpu1": { "extends": ["debug", "gpu1"] }, + "bench_gpu0": { "extends": ["bench", "gpu0"] } +} +``` + +Запуск: + +```bash +./program --spla-config=gpu1 +./program --spla-config=debug +./program --spla-config=debug_gpu1 +./program --spla-config=bench_gpu0 +``` + +Конфигурации, наследуемые через `extends`, применяются по порядку: каждый следующий родитель переопределяет предыдущего, а параметры самой конфигурации переопределяют всех родителей. Циклическое наследование обнаруживается и приводит к ошибке. + +## Сценарий 4. Запуск в CI с файлом из репозитория + +Вам нужно запустить тесты в CI с отдельным файлом конфигурации. + +В среде CI неудобно и нежелательно трогать системный и пользовательский файлы конфигурации, а конфигурации тестов должны лежать в репозитории. Поэтому конфигурации описывают в отдельном файле внутри репозитория и указывают путь к нему при запуске вместе с именем конфигурации - это аргументы командной строки `--spla-config-file` и `--spla-config`. + +``` +my_project/ +├── .github/ +│ └── workflows/ +│ ├── ci.yml +│ └── ci_spla_conf.json +├── src/ +└── tests/ +``` + +### ci_spla_conf.json + +```json +{ + "test_cpu": { + "backend": "cpu", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 1 + }, + "test_gpu0": { + "backend": "by_index", + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", + "queues_count": 2, + "profiling": false, + "allocator_type": "general", + "verbosity": 0 + }, + "test_gpu1": { + "backend": "by_index", + "platform_index": 0, + "device_index": 1, + "if_gpu_unavailable": "abort", + "queues_count": 2, + "profiling": false, + "allocator_type": "linear", + "linear_alloc_size": 8, + "verbosity": 0 + } +} +``` + +### ci.yml + +```yml +name: CI + +on: [push, pull_request] + +jobs: + test: + name: Test (${{ matrix.config }}) + runs-on: [self-hosted, gpu] + + strategy: + fail-fast: false + matrix: + config: [test_cpu, test_gpu0, test_gpu1] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyspla pytest + + - name: Run tests + run: python src/my_app.py --spla-config-file=.github/workflows/ci_spla_conf.json --spla-config=${{ matrix.config }} +``` + +Путь к файлу и имя конфигурации передаются при запуске как аргументы команды, а не через переменные окружения - в CI это делает команду запуска самодостаточной и воспроизводимой. + +## Приоритет источников конфигурации + +Источники применяются в порядке убывания приоритета: параметры из более приоритетного источника переопределяют менее приоритетные. Это важно для сценариев: любой флаг или переменная окружения перебивает значения из файлов. + +| # | Источник | +|---:|:---| +| 1 | Аргументы командной строки (`--spla-*`) | +| 2 | Переменные окружения (`SPLA_*`) | +| 3 | Файл с явно указанным путём (`--spla-config-file`) | +| 4 | Пользовательский конфигурационный файл | +| 5 | Системный конфигурационный файл | +| 6 | Конфигурационный файл, поставляемый библиотекой | + +Если имя конфигурации не указано, используется конфигурация `"default"` из файла, поставляемого библиотекой. Подробно о порядке сбора и слиянии источников - в [User Manual](UserManual.md#обзор-механизма-конфигурирования). + +## Где лежат файлы конфигурации + +- **Поставляемый библиотекой** - рядом с файлом библиотеки (в пакете pyspla - внутри установленного пакета). +- **Системный** - Linux: `/etc/spla/spla_conf.json`. +- **Пользовательский** - Linux: `~/.config/spla/spla_conf.json`. +- **Явный** - любой путь через `--spla-config-file`. + +Пути для macOS и Windows и правила «файла нет / файл не открывается» - в [User Manual](UserManual.md#конфигурационные-файлы). \ No newline at end of file diff --git a/docs/UserManual.md b/docs/UserManual.md new file mode 100644 index 000000000..f7dd6d371 --- /dev/null +++ b/docs/UserManual.md @@ -0,0 +1,305 @@ +# User Manual + +Мануал по механизму конфигурирования библиотеки spla. Это справочник: полное описание параметров, источников конфигурации, правил валидации и статусов. Практические сценарии использования приведены в [User Guide](UserGuide.md). + +## Содержание + +1. [НАЗВАНИЕ](#название) +2. [ОБЗОР МЕХАНИЗМА КОНФИГУРИРОВАНИЯ](#обзор-механизма-конфигурирования) +3. [ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ](#параметры-командной-строки) +4. [ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ](#переменные-окружения) +5. [КОНФИГУРАЦИОННЫЕ ФАЙЛЫ](#конфигурационные-файлы) +6. [КОНФИГУРАЦИИ И НАСЛЕДОВАНИЕ](#конфигурации-и-наследование) +7. [ВАЛИДАЦИЯ ПАРАМЕТРОВ](#валидация-параметров) +8. [СТАТУСЫ И ПОВЕДЕНИЕ ПРИ ОШИБКАХ](#статусы-и-поведение-при-ошибках) + +## НАЗВАНИЕ + +spla - фреймворк для математических вычислений с ускорением на GPU. Библиотека предоставляет примитивы разреженной линейной алгебры (матрицы, векторы, скаляры) и широкий спектр операций. + +Для большинства пользователей важно, на каком устройстве будет запускаться их проект, поэтому библиотека предоставляет механизм конфигурирования: явное указание GPU, OpenCL-платформы, количества очередей команд и других параметров, влияющих на производительность и удобство пользователя. + +## ОБЗОР МЕХАНИЗМА КОНФИГУРИРОВАНИЯ + +Конфигурация spla собирается из шести источников, применяемых в порядке убывания приоритета. + +| # | Источник | Как задаётся | +|---:|:---|:---| +| 1 | Аргументы командной строки | флаги `--spla-*` | +| 2 | Переменные окружения | переменные `SPLA_*` | +| 3 | Файл с явно указанным путём | флаг `--spla-config-file` или `SPLA_CONFIG_FILE` | +| 4 | Пользовательский файл | `~/.config/spla/spla_conf.json` (Linux) и аналоги | +| 5 | Системный файл | `/etc/spla/spla_conf.json` (Linux) и аналоги | +| 6 | Файл библиотеки | `spla_conf.json` рядом с файлом библиотеки | + +Порядок сбора: + +1. Читаются конфигурационные файлы (6 → 5 → 4 → 3) и **сливаются по именам конфигураций**: одноимённые конфигурации из разных файлов объединяются по параметрам, уникальные добавляются. +2. Выбирается активная конфигурация: имя из `--spla-config` / `SPLA_CONFIG`, по умолчанию - `"default"`. +3. Применяется выбранная конфигурация вместе с родителями из `extends`. +4. Поверх применяются переменные окружения, затем аргументы командной строки (наивысший приоритет). + +Результат попадает в итоговую конфигурацию, которая используется при инициализации ускорителя (выбор платформы и устройства, создание очередей команд, аллокатора, уровня логирования). + +## ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ + +Все флаги spla начинаются с `--spla-`. Флаги, не начинающиеся с `--spla-`, принадлежат программе, использующей библиотеку, и игнорируются механизмом конфигурирования. + +| Флаг | Тип | Описание | +|:---|:---|:---| +| `--spla-help` | - | Вывести справку и завершиться | +| `--spla-version` | - | Вывести версию библиотеки и завершиться | +| `--spla-config` | string | Имя конфигурации для применения. По умолчанию используется конфигурация `"default"` | +| `--spla-config-file` | path | Путь к конфигурационному файлу. | +| `--spla-backend` | string | Тип устройства: `gpu`, `cpu`, `any`, `by_index` | +| `--spla-platform-index` | int | Индекс OpenCL-платформы. Только при `backend=by_index` | +| `--spla-device-index` | int | Индекс OpenCL-устройства внутри платформы. Только при `backend=by_index` | +| `--spla-if-gpu-unavailable` | string | Поведение при недоступности GPU: `use_cpu` - переключиться на CPU, `abort` - вернуть ошибку | +| `--spla-queues-count` | int | Количество командных очередей OpenCL | +| `--spla-profiling` | bool | Профилирование командных очередей: `true`, `false` | +| `--spla-allocator-type` | string | Тип аллокатора: `general`, `linear` | +| `--spla-linear-alloc-size` | int | Размер линейного аллокатора в байтах. Требуется при `allocator_type=linear`, игнорируется при `general` | +| `--spla-verbosity` | int | Уровень логирования: `0` - нет вывода, `1` - только ошибки, `2` - ошибки и предупреждения, `3` - все сообщения | + +### Пример + +```bash +./my_program --spla-config-file=/etc/spla/spla_conf.json --spla-config=bench --spla-verbosity=0 +``` + +## ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ + +Для каждого параметра командной строки (кроме `--spla-help` и `--spla-version`) существует аналог в виде переменной окружения. + +| Переменная | Аналог флага | +|:---|:---| +| `SPLA_CONFIG` | `--spla-config` | +| `SPLA_CONFIG_FILE` | `--spla-config-file` | +| `SPLA_BACKEND` | `--spla-backend` | +| `SPLA_PLATFORM_INDEX` | `--spla-platform-index` | +| `SPLA_DEVICE_INDEX` | `--spla-device-index` | +| `SPLA_IF_GPU_UNAVAILABLE` | `--spla-if-gpu-unavailable` | +| `SPLA_QUEUES_COUNT` | `--spla-queues-count` | +| `SPLA_PROFILING` | `--spla-profiling` | +| `SPLA_ALLOCATOR_TYPE` | `--spla-allocator-type` | +| `SPLA_LINEAR_ALLOC_SIZE` | `--spla-linear-alloc-size` | +| `SPLA_VERBOSITY` | `--spla-verbosity` | + +### Пример + +```bash +SPLA_CONFIG=bench SPLA_VERBOSITY=1 ./my_program +``` + +## КОНФИГУРАЦИОННЫЕ ФАЙЛЫ + +Формат файла - JSON. Файл состоит из набора именованных конфигураций,каждая конфигурация - это набор параметров библиотеки. + +### Ключи конфигурации + +| Ключ | Тип | Описание | Требования | +|:---|:---|:---|:---| +| `extends` | array of string | Список конфигураций-родителей | Имена конфигураций со всех уровней файлов | +| `backend` | string | Тип устройства: `gpu`, `cpu`, `any`, `by_index` | Обязателен | +| `platform_index` | int | Индекс OpenCL-платформы | Обязателен при `backend=by_index`, иначе игнорируется | +| `device_index` | int | Индекс OpenCL-устройства | Обязателен при `backend=by_index`, иначе игнорируется | +| `if_gpu_unavailable` | string | Поведение при недоступности GPU: `use_cpu`, `abort` | Обязателен при `backend != cpu`, при `backend=cpu` игнорируется | +| `queues_count` | int | Количество командных очередей | Обязателен, ≥ 1 | +| `profiling` | bool | Профилирование очередей | Обязателен | +| `allocator_type` | string | Тип аллокатора: `general`, `linear` | Обязателен | +| `linear_alloc_size` | int | Размер линейного аллокатора (байт) | Обязателен при `allocator_type=linear`, при `general` игнорируется | +| `verbosity` | int | Уровень логирования 0..3 | Обязателен | + +### Файл, поставляемый библиотекой + +Имя конфигурации `"default"` может быть определено **только** в файле, поставляемом библиотекой. Определение конфигурации с именем `"default"` в любом другом файле - ошибка парсинга. + +Поставляемый файл имеет следующую структуру: + +```json +{ + "default": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", + + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + + "verbosity": 2 + } +} +``` + +### Расположение файлов + +**Файл библиотеки** - рядом с файлом библиотеки: Windows - рядом с DLL, Linux/macOS - рядом с `.so`/`.dylib` (путь определяется через адрес загруженной библиотеки). В составе пакета pyspla - внутри директории установленного Python-пакета. + +**Системный файл:** + +> Linux: `/etc/spla/spla_conf.json` \ +> macOS: `/Library/Application Support/spla/spla_conf.json` \ +> Windows: `%ProgramData%\spla\spla_conf.json` + +**Пользовательский файл:** + +> Linux: `~/.config/spla/spla_conf.json` \ +> macOS: `~/Library/Application Support/spla/spla_conf.json` \ +> Windows: `%APPDATA%\spla\spla_conf.json` + +**Файл, заданный явно** - любой путь, заданный через `--spla-config-file` / `SPLA_CONFIG_FILE`. + +### Семантика отсутствующих и неоткрывающихся файлов + +| Файл | Отсутствует | Существует, но не открывается | +|:---|:---|:---| +| Файл библиотеки | ошибка `FileNotExists` (обязателен) | ошибка `OpenFileError` | +| Системный | пропуск | ошибка `OpenFileError` | +| Пользовательский | пропуск | ошибка `OpenFileError` | +| Явный (если указан) | ошибка `FileNotExists` | ошибка `OpenFileError` | + +## КОНФИГУРАЦИИ И НАСЛЕДОВАНИЕ + +### Выбор активной конфигурации + +```bash +./program --spla-config=gpu1 # флаг +SPLA_CONFIG=gpu1 ./program # или переменная окружения +``` + +Если имя не указано, используется конфигурация `"default"` из файла, поставляемого библиотекой. + +### Слияние файлов + +Конфигурации из файлов библиотеки, системного, пользовательского и явного сливаются по именам: одноимённые конфигурации объединяются по параметрам, уникальные добавляются. Параметры конфигурации из файла с более высоким приоритетом переопределяют параметры одноимённой конфигурации из файла с более низким приоритетом. + +### Наследование `extends` + +Если конфигурация содержит поле `extends`, библиотека сначала применяет указанные в нём конфигурации по порядку: последняя в списке переопределяет предыдущие. Параметры самой конфигурации применяются последними и переопределяют всех родителей. + +Если конфигурация не содержит `extends`, применяются только её собственные параметры. + +Имена в `extends` берутся из всех конфигураций, определённых во всех файлах. Это позволяет наследовать конфигурации, определённые на другом уровне, например пользовательская конфигурация может наследовать `"default"` из файла библиотеки. + +Циклическое наследование обнаруживается и приводит к статусу `ConfigurationCycle`. + +Пример цикла - конфигурации наследуют друг друга напрямую: + +```json +{ + "a": { "extends": ["b"], "backend": "gpu" }, + "b": { "extends": ["a"], "backend": "cpu" } +} +``` + +Такая конфигурация отклоняется при загрузке (`ConfigurationCycle`). Циклом является и самоссылка (`"extends": ["a"]` внутри конфигурации `a`). Ромбовидное наследование (`a` → `b`, `a` → `c`, где `b` и `c` оба наследуют `d`) циклом не является. + +### Пример + +Файл, поставляемый библиотекой: + +```json +{ + "default": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + "verbosity": 2 + } +} +``` + +Пользовательский файл: + +```json +{ + "gpu0": { + "extends": ["default"], + "backend": "by_index", + "platform_index": 0, + "device_index": 0, + "if_gpu_unavailable": "abort", + "queues_count": 1, + "profiling": true + } +} +``` + +Итоговый набор параметров конфигурации `gpu0`: + +| Параметр | Значение | Источник | +|:---|:---|:---| +| backend | `by_index` | конфигурация `gpu0` | +| platform_index | `0` | конфигурация `gpu0` | +| device_index | `0` | конфигурация `gpu0` | +| if_gpu_unavailable | `abort` | конфигурация `gpu0` | +| queues_count | `1` | файл библиотеки (`default`) | +| profiling | `true` | конфигурация `gpu0` | +| allocator_type | `general` | файл библиотеки (`default`) | +| verbosity | `2` | файл библиотеки (`default`) | + +## ВАЛИДАЦИЯ ПАРАМЕТРОВ + +После сборки конфигурация из всех источников проходит валидацию. + +### Ошибки (конфигурация недействительна) + +| Параметр | Требование | +|:---|:---| +| `backend` | Обязателен, одно из: `gpu`, `cpu`, `any`, `by_index` | +| `platform_index`, `device_index` | Обязательны при `backend=by_index`, должны быть ≥ 0 | +| `if_gpu_unavailable` | Обязателен при `backend != cpu`, одно из: `use_cpu`, `abort` | +| `queues_count` | Обязателен, ≥ 1 | +| `profiling` | Обязателен | +| `allocator_type` | Обязателен, одно из: `general`, `linear` | +| `linear_alloc_size` | Обязателен при `allocator_type=linear` | +| `verbosity` | Обязателен, 0..3 | + +### Предупреждения (параметр игнорируется, но конфигурация действительна) + +| Ситуация | Сообщение | +|:---|:---| +| `platform_index`/`device_index` заданы при `backend != by_index` | параметр игнорируется | +| `if_gpu_unavailable` задан при `backend=cpu` | параметр игнорируется | +| `linear_alloc_size` задан при `allocator_type=general` | параметр игнорируется | + +### Поведение при недоступности устройства + +Реализовано в инициализации ускорителя: + +| Конфигурация | GPU доступен | GPU недоступен | +|:---|:---|:---| +| `backend=gpu`, `if_gpu_unavailable=use_cpu` | используется GPU | ищется OpenCL-устройство CPU, нет - `DeviceNotFound` | +| `backend=gpu` / `any`, `if_gpu_unavailable=abort` | используется GPU | ошибка `DeviceNotFound`, при запуске через `pyspla` поднимается `SplaFailedInitialize` | +| `backend=cpu` | - | ищется OpenCL-устройство CPU, нет - `DeviceNotFound` | +| `backend=by_index` | - | выбирается платформа/устройство по индексам, устройство недоступно - `DeviceNotFound` | + +## СТАТУСЫ И ПОВЕДЕНИЕ ПРИ ОШИБКАХ + +Механизм конфигурирования возвращает один из следующих статусов. + +| Статус | Значение | +|:---|:---| +| `Ok` | Конфигурация собрана и валидна | +| `HelpRequested` | Запрошена справка (`--spla-help`) - текст уже выведен | +| `VersionRequested` | Запрошена версия (`--spla-version`) - уже выведена | +| `CliOrEnvParseError` | Ошибка разбора аргументов командной строки или переменных окружения | +| `FileNotExists` | Отсутствует обязательный файл (файл библиотеки или явно указанный) | +| `OpenFileError` | Файл существует, но не может быть открыт | +| `ParseConfError` | Ошибка разбора JSON, неверный тип значения или `"default"` в не-библиотечном файле | +| `ConfigurationNotFound` | Указанное имя конфигурации не найдено ни в одном файле | +| `ConfigurationCycle` | Обнаружен цикл в `extends` | +| `MissedParameters` | Отсутствуют обязательные параметры | +| `PlatformNotFound` / `DeviceNotFound` | Устройство по конфигурации недоступно | +| `InvalidConfigParams` | Недопустимое значение параметра | + +### Поведение в CLI + +Инструмент командной строки `spla`: + +- `spla --softcheck` - проверка работоспособности окружения (конфигурирование, инициализация OpenCL, задание 2 + 3), +- `spla --spla-help` - справка, код возврата 0, +- `spla --spla-version` - версия библиотеки (например, `SPLA version: 0.0.5`), код возврата 0, +- при ошибке конфигурирования - сообщение об ошибке и код возврата 1. \ No newline at end of file diff --git a/include/spla.h b/include/spla.h index 907865fab..ad4897b4e 100644 --- a/include/spla.h +++ b/include/spla.h @@ -135,6 +135,7 @@ typedef void(spla_MessageCallback)(spla_Status, const char* message, const char* SPLA_API void spla_Library_finalize(); SPLA_API spla_Status spla_Library_initialize(); +SPLA_API spla_Status spla_Configure(int argc, char** argv); SPLA_API spla_Status spla_Library_set_accelerator(spla_AcceleratorType accelerator); SPLA_API spla_Status spla_Library_set_platform(int index); SPLA_API spla_Status spla_Library_set_device(int index); diff --git a/python/pyspla/bridge.py b/python/pyspla/bridge.py index 808f6ff17..583df12cf 100644 --- a/python/pyspla/bridge.py +++ b/python/pyspla/bridge.py @@ -35,6 +35,7 @@ ] import os +import sys import ctypes import pathlib import platform @@ -66,6 +67,10 @@ class SplaFailedInitialize(SplaError): pass +class SplaFailedConfigure(SplaError): + pass + + class SplaNoAcceleration(SplaError): pass @@ -191,6 +196,8 @@ def load_library(lib_path): _spla.spla_Library_finalize.argtypes = [] _spla.spla_Library_initialize.restype = _status_t _spla.spla_Library_initialize.argtypes = [] + _spla.spla_Configure.restype = _status_t + _spla.spla_Configure.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)] _spla.spla_Library_set_accelerator.restype = _status_t _spla.spla_Library_set_accelerator.argtypes = [_enum_t] _spla.spla_Library_set_platform.restype = _status_t @@ -616,6 +623,36 @@ def default_callback(status, msg, file, function, line, user_data): print(f"pyspla: [{decoded_file}:{line}] {_status_mapping[status]}: {decoded_msg}") +def filter_spla_args(argv): + """Filter sys.argv, keeping only spla options (starting with --spla-)""" + result = [] + skip_next = False + for i, arg in enumerate(argv): + if skip_next: + skip_next = False + continue + if arg.startswith("--spla-"): + result.append(arg) + if i + 1 < len(argv) and not argv[i + 1].startswith("-"): + result.append(argv[i + 1]) + skip_next = True + return result + + +def configure(): + """Configure spla from command line arguments""" + if _spla: + args = filter_spla_args(sys.argv[1:]) + argc = len(args) + argv = (ctypes.c_char_p * argc)(*[arg.encode("utf-8") for arg in args]) + status = _spla.spla_Configure(argc, argv) + + if status not in (0, 1, 2): + raise SplaFailedConfigure( + f"spla configuration failed with status {status}" + ) + + def init_library(): if _spla: if _spla.spla_Library_initialize() != 0: @@ -656,6 +693,7 @@ def initialize(): raise Exception(f"no compiled spla file {TARGET} to load") load_library(_spla_path) + configure() init_library() _default_callback = _callback_t(default_callback) diff --git a/python/pyspla/spla_conf.json b/python/pyspla/spla_conf.json new file mode 100644 index 000000000..acdc385a2 --- /dev/null +++ b/python/pyspla/spla_conf.json @@ -0,0 +1,12 @@ +{ + "default": { + "backend": "gpu", + "if_gpu_unavailable": "use_cpu", + + "queues_count": 1, + "profiling": false, + "allocator_type": "general", + + "verbosity": 2 + } +} diff --git a/python/setup.py b/python/setup.py index 695e42f8a..ddf51b11c 100644 --- a/python/setup.py +++ b/python/setup.py @@ -73,7 +73,7 @@ def get_lib_names(): ], packages=["pyspla"], package_dir={'': '.'}, - package_data={'': get_lib_names()}, + package_data={'': get_lib_names() + ["spla_conf.json"]}, python_requires=">=3.0", include_package_data=True ) diff --git a/src/binding/c_config.hpp b/src/binding/c_config.hpp index 4e1302570..2a89e2514 100644 --- a/src/binding/c_config.hpp +++ b/src/binding/c_config.hpp @@ -28,6 +28,7 @@ #ifndef SPLA_C_CONFIG_HPP #define SPLA_C_CONFIG_HPP +#include #include #include @@ -48,6 +49,10 @@ static spla_Status to_c_status(spla::Status status) { return static_cast(status); } +static spla_Status to_c_status(spla::ConfigStatus status) { + return static_cast(status); +} + static spla::AcceleratorType from_c_accelerator_type(spla_AcceleratorType accelerator) { return static_cast(accelerator); } diff --git a/src/binding/c_library.cpp b/src/binding/c_library.cpp index 9f907a8d6..2ce9112cc 100644 --- a/src/binding/c_library.cpp +++ b/src/binding/c_library.cpp @@ -26,12 +26,25 @@ /**********************************************************************************/ #include "c_config.hpp" +#include void spla_Library_finalize() { spla::Library::get()->finalize(); } spla_Status spla_Library_initialize() { - return spla::Library::get() ? SPLA_STATUS_OK : SPLA_STATUS_ERROR; + auto* lib = spla::Library::get(); + if (!lib) return SPLA_STATUS_ERROR; + + if (spla::config_final.backend.has_value() && + lib->get_accelerator() == nullptr && + spla::config_final.if_gpu_unavailable.value_or("") != "use_cpu") { + return SPLA_STATUS_ERROR; + } + + return SPLA_STATUS_OK; +} +spla_Status spla_Configure(int argc, char** argv) { + return to_c_status(spla::configure(argc, argv)); } spla_Status spla_Library_set_accelerator(spla_AcceleratorType accelerator) { return to_c_status(spla::Library::get()->set_accelerator(from_c_accelerator_type(accelerator))); diff --git a/src/core/cl_config_status.hpp b/src/core/cl_config_status.hpp new file mode 100644 index 000000000..b1260f333 --- /dev/null +++ b/src/core/cl_config_status.hpp @@ -0,0 +1,48 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/JetBrains-Research/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +namespace spla { + + enum ConfigStatus { + Ok, + HelpRequested, + VersionRequested, + CliOrEnvParseError, + FileNotExists, + OpenFileError, + ParseConfError, + ConfigurationNotFound, + ConfigurationCycle, + MissedParameters, + PlatformNotFound, + DeviceNotFound, + InvalidConfigParams + }; + +}// namespace spla \ No newline at end of file diff --git a/src/core/configure.cpp b/src/core/configure.cpp new file mode 100644 index 000000000..36cc705f5 --- /dev/null +++ b/src/core/configure.cpp @@ -0,0 +1,578 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/SparseLinearAlgebra/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "configure.hpp" + +#include +#include +#include +#include + +#ifdef _WIN32 + #include +#else + #include +#endif + +namespace spla { + + ConfigFile config_default; + ConfigFile config_system; + ConfigFile config_user; + ConfigFile config_explicit; + CliMeta config_cli_meta; + Configuration config_cli_and_env; + Configuration config_final; + + + void Configuration::merge(const Configuration& source) { + if (source.extends.has_value()) extends = source.extends; + if (source.backend.has_value()) backend = source.backend; + if (source.platform_index.has_value()) platform_index = source.platform_index; + if (source.device_index.has_value()) device_index = source.device_index; + if (source.if_gpu_unavailable.has_value()) if_gpu_unavailable = source.if_gpu_unavailable; + if (source.queues_count.has_value()) queues_count = source.queues_count; + if (source.profiling.has_value()) profiling = source.profiling; + if (source.allocator_type.has_value()) allocator_type = source.allocator_type; + if (source.linear_alloc_size.has_value()) linear_alloc_size = source.linear_alloc_size; + if (source.verbosity.has_value()) verbosity = source.verbosity; + } + + void Configuration::reset() { + *this = Configuration{}; + } + + + void ConfigFile::merge(const ConfigFile& source) { + if (!source.configs.has_value()) return; + if (!configs.has_value()) configs.emplace(); + + for (const auto& [name, source_config] : *source.configs) { + (*configs)[name].merge(source_config); + } + } + + void ConfigFile::reset() { + configs.reset(); + } + + + std::string get_spla_version() { +#ifndef SPLA_VERSION + #define SPLA_VERSION "0.0.0" +#endif + return "SPLA version: " SPLA_VERSION; + } + + + std::string get_default_config_path() { +#ifdef _WIN32 + HMODULE hModule; + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + (LPCTSTR) &get_default_config_path, &hModule); + char path[MAX_PATH]; + GetModuleFileName(hModule, path, MAX_PATH); + std::string dir = path; + dir = dir.substr(0, dir.find_last_of("\\/")); + return dir + "\\spla_conf.json"; +#elif defined(__APPLE__) || defined(__linux__) + Dl_info info; + dladdr((void*) &get_default_config_path, &info); + std::string path = info.dli_fname; + std::string dir = path.substr(0, path.find_last_of("/")); + return dir + "/spla_conf.json"; +#else + #error "spla supports only Windows, macOS and Linux" +#endif + } + + std::string get_system_config_path() { +#ifdef _WIN32 + const char* program_data = std::getenv("PROGRAMDATA"); + if (program_data) { + return std::string(program_data) + "\\spla\\spla_conf.json"; + } + return "C:\\ProgramData\\spla\\spla_conf.json"; + +#elif defined(__APPLE__) + return "/Library/Application Support/spla/spla_conf.json"; + +#elif defined(__linux__) + return "/etc/spla/spla_conf.json"; + +#else + #error "spla supports only Windows, macOS and Linux" +#endif + } + + + std::string get_home_directory() { +#ifdef _WIN32 + const char* home = std::getenv("USERPROFILE"); + if (home) return std::string(home); + + const char* drive = std::getenv("HOMEDRIVE"); + const char* path = std::getenv("HOMEPATH"); + if (drive && path) return std::string(drive) + std::string(path); + throw std::runtime_error("Cannot determine home directory"); + +#elif defined(__APPLE__) || defined(__linux__) + const char* home = std::getenv("HOME"); + if (home) return std::string(home); + + struct passwd* pw = getpwuid(getuid()); + if (pw) return std::string(pw->pw_dir); + throw std::runtime_error("Cannot determine home directory"); + +#else + #error "spla supports only Windows, macOS and Linux" +#endif + } + + + std::string get_user_config_path() { + std::string home = get_home_directory(); + +#ifdef _WIN32 + const char* app_data = std::getenv("APPDATA"); + if (app_data) return std::string(app_data) + "\\spla\\spla_conf.json"; + return home + "\\AppData\\Roaming\\spla\\spla_conf.json"; + +#elif defined(__APPLE__) + return home + "/Library/Application Support/spla/spla_conf.json"; + +#elif defined(__linux__) || defined(__unix__) + return home + "/.config/spla/spla_conf.json"; + +#else + #error "spla supports only Windows, macOS and Linux" +#endif + } + + + ConfigStatus parse_cli_and_env(int argc, char** argv, CliMeta& meta, Configuration& cfg) { + CLI::App app{"SPLA configuration"}; + app.name("spla"); + + app.allow_extras(); + + app.set_help_flag("--spla-help", "Show help and exit"); + app.add_flag("--spla-version", meta.version, "Show version and exit"); + + app.add_option("--spla-config", meta.configuration, + "Name of the configuration to apply.\n" + "If not specified, the configuration named 'default' is used.\n" + "Config key: configuration") + ->envname("SPLA_CONFIG"); + + app.add_option("--spla-config-file", meta.path_to_conf, + "Path to a configuration file to load explicitly.\n" + "Has higher priority than system and user configuration files,\n" + "but lower than command-line arguments and environment variables.\n" + "Config key: path_to_conf") + ->envname("SPLA_CONFIG_FILE"); + + app.add_option("--spla-backend", cfg.backend, + "Device type to use:\n" + " gpu - only GPU\n" + " cpu - only CPU\n" + " any - any available device\n" + " by_index - select by platform_index and device_index\n" + "Config key: backend") + ->envname("SPLA_BACKEND"); + + app.add_option("--spla-platform-index", cfg.platform_index, + "OpenCL platform index\n" + "Used only with backend=by_index.\n" + "Config key: platform_index") + ->envname("SPLA_PLATFORM_INDEX"); + + app.add_option("--spla-device-index", cfg.device_index, + "OpenCL device index\n" + "Used only with backend=by_index.\n" + "Config key: device_index") + ->envname("SPLA_DEVICE_INDEX"); + + app.add_option("--spla-if-gpu-unavailable", cfg.if_gpu_unavailable, + "Behavior when GPU is unavailable:\n" + " use_cpu - switch to CPU\n" + " abort - return error\n" + "Config key: if_gpu_unavailable") + ->envname("SPLA_IF_GPU_UNAVAILABLE"); + + app.add_option("--spla-queues-count", cfg.queues_count, + "Number of command queues\n" + "Config key: queues_count") + ->envname("SPLA_QUEUES_COUNT"); + + app.add_option("--spla-profiling", cfg.profiling, + "Enable profiling of command queues: true or false\n" + "Config key: profiling") + ->envname("SPLA_PROFILING"); + + app.add_option("--spla-allocator-type", cfg.allocator_type, + "Allocator type:\n" + " general\n" + " linear\n" + "Config key: allocator_type") + ->envname("SPLA_ALLOCATOR_TYPE"); + + app.add_option("--spla-linear-alloc-size", cfg.linear_alloc_size, + "Linear allocator size in bytes\n" + "Required for allocator_type=linear. Ignored for general.\n" + "Config key: linear_alloc_size") + ->envname("SPLA_LINEAR_ALLOC_SIZE"); + + app.add_option("--spla-verbosity", cfg.verbosity, + "Verbosity level:\n" + " 0 - no output\n" + " 1 - errors only\n" + " 2 - errors and warnings\n" + " 3 - all messages\n" + "Config key: verbosity") + ->envname("SPLA_VERBOSITY"); + + std::vector args; + if (argv != nullptr && argc > 0) { + args.reserve(static_cast(argc)); + for (int i = argc - 1; i >= 0; --i) { + args.emplace_back(argv[i]); + } + } + + try { + app.parse(std::move(args)); + } catch (const CLI::CallForHelp& e) { + std::cout << app.help() << std::endl; + return ConfigStatus::HelpRequested; + } catch (const CLI::ParseError& e) { + std::cerr << "[spla:cli_env] ERROR: failed to parse: " << e.what() << std::endl; + return ConfigStatus::CliOrEnvParseError; + } + + if (meta.version.value_or(false)) { + std::cout << get_spla_version() << std::endl; + return ConfigStatus::VersionRequested; + } + + return ConfigStatus::Ok; + } + + + ConfigStatus parse_file(const std::string& path, ConfigFile& cfg, bool allow_default) { + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "[spla:config] ERROR: cannot open: " << path << std::endl; + return ConfigStatus::OpenFileError; + } + + try { + nlohmann::json data = nlohmann::json::parse(file); + if (!cfg.configs.has_value()) cfg.configs.emplace(); + + for (auto& [name, value] : data.items()) { + if (!allow_default && name == "default") { + std::cerr << "[spla:config] ERROR: '" << path << "': " + << "configuration 'default' can only be defined in the library configuration file" + << std::endl; + return ConfigStatus::ParseConfError; + } + + Configuration config; + if (value.contains("extends")) config.extends = value["extends"].get>(); + if (value.contains("backend")) config.backend = value["backend"].get(); + if (value.contains("platform_index")) config.platform_index = value["platform_index"].get(); + if (value.contains("device_index")) config.device_index = value["device_index"].get(); + if (value.contains("if_gpu_unavailable")) config.if_gpu_unavailable = value["if_gpu_unavailable"].get(); + if (value.contains("queues_count")) config.queues_count = value["queues_count"].get(); + if (value.contains("profiling")) config.profiling = value["profiling"].get(); + if (value.contains("allocator_type")) config.allocator_type = value["allocator_type"].get(); + if (value.contains("linear_alloc_size")) config.linear_alloc_size = value["linear_alloc_size"].get(); + if (value.contains("verbosity")) config.verbosity = value["verbosity"].get(); + + (*cfg.configs)[name].merge(config); + } + + return ConfigStatus::Ok; + + } catch (const nlohmann::json::exception& e) { + std::cerr << "[spla:config] ERROR: failed to parse '" + << path << "': " << e.what() << std::endl; + return ConfigStatus::ParseConfError; + } + } + + + Configuration apply_extends(const std::map& configs, + const std::string& name, + std::set& stack) { + if (stack.count(name)) { + throw std::runtime_error("extends cycle detected: " + name); + } + stack.insert(name); + + auto it = configs.find(name); + if (it == configs.end()) { + throw std::runtime_error("extends configuration not found: " + name); + } + + const Configuration& source = it->second; + Configuration result; + + if (source.extends.has_value()) { + for (const auto& parent_name : *source.extends) { + result.merge(apply_extends(configs, parent_name, stack)); + } + } + result.merge(source); + stack.erase(name); + return result; + } + + ConfigStatus apply_configuration(const ConfigFile& file, const std::string& name, Configuration& cfg) { + + std::set stack; + try { + cfg = apply_extends(*file.configs, name, stack); + } catch (const std::runtime_error& e) { + const std::string msg = e.what(); + if (msg.find("cycle") != std::string::npos) { + std::cerr << "[spla:configure] ERROR: extends cycle detected in configuration '" + << name << "'" << std::endl; + return ConfigStatus::ConfigurationCycle; + } + std::cerr << "[spla:configure] ERROR: " << msg << std::endl; + return ConfigStatus::ConfigurationNotFound; + } + + return ConfigStatus::Ok; + } + + + ConfigStatus validation(const Configuration& cfg) { + if (!cfg.backend.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: backend" << std::endl; + return ConfigStatus::MissedParameters; + } + + const std::string& backend = *cfg.backend; + if (backend != "gpu" && backend != "cpu" && + backend != "any" && backend != "by_index") { + std::cerr << "[spla:validation] ERROR: backend must be " + << "'gpu', 'cpu', 'any' or 'by_index' (got '" << backend << "')" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + if (backend == "by_index") { + if (!cfg.platform_index.has_value()) { + std::cerr << "[spla:validation] ERROR: platform_index is required " + << "when backend='by_index'" << std::endl; + return ConfigStatus::MissedParameters; + } + if (!cfg.device_index.has_value()) { + std::cerr << "[spla:validation] ERROR: device_index is required " + << "when backend='by_index'" << std::endl; + return ConfigStatus::MissedParameters; + } + + if (*cfg.platform_index < 0) { + std::cerr << "[spla:validation] ERROR: platform_index must be >= 0 (got " + << *cfg.platform_index << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + if (*cfg.device_index < 0) { + std::cerr << "[spla:validation] ERROR: device_index must be >= 0 (got " + << *cfg.device_index << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + } else if (cfg.platform_index.has_value()) { + std::cerr << "[spla:validation] WARNING: platform_index: " << *cfg.platform_index + << " ignored for backend='" << backend << "'" << std::endl; + + } else if (cfg.device_index.has_value()) { + std::cerr << "[spla:validation] WARNING: device_index " << *cfg.device_index + << "ignored for backend='" << backend << "'" << std::endl; + } + + + if (backend != "cpu" && !cfg.if_gpu_unavailable.has_value()) { + std::cerr << "[spla:validation] ERROR: if_gpu_unavailable is required " + << "when backend=" << backend << std::endl; + return ConfigStatus::MissedParameters; + } + if (cfg.if_gpu_unavailable.has_value()) { + const std::string& behavior = *cfg.if_gpu_unavailable; + if (behavior != "use_cpu" && behavior != "abort") { + std::cerr << "[spla:validation] ERROR: if_gpu_unavailable must be " + << "'use_cpu' or 'abort' (got '" << behavior << "')" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + if (backend == "cpu") { + std::cerr << "[spla:validation] WARNING: if_gpu_unavailable " + << "ignored for backend='cpu'" << std::endl; + } + } + + + if (!cfg.queues_count.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: queues_count" << std::endl; + return ConfigStatus::MissedParameters; + } + if (*cfg.queues_count < 1) { + std::cerr << "[spla:validation] ERROR: queues_count must be >= 1 (got " + << *cfg.queues_count << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + + if (!cfg.profiling.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: profiling" << std::endl; + return ConfigStatus::MissedParameters; + } + + + if (!cfg.allocator_type.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: allocator_type" << std::endl; + return ConfigStatus::MissedParameters; + } + if (*cfg.allocator_type != "general" && *cfg.allocator_type != "linear") { + std::cerr << "[spla:validation] ERROR: allocator_type must be " + << "'general' or 'linear' (got '" << *cfg.allocator_type << "')" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + if (*cfg.allocator_type == "linear") { + if (!cfg.linear_alloc_size.has_value()) { + std::cerr << "[spla:validation] ERROR: linear_alloc_size is required " + << "when allocator_type='linear'" << std::endl; + return ConfigStatus::MissedParameters; + } + } else if (cfg.linear_alloc_size.has_value()) { + std::cerr << "[spla:validation] WARNING: linear_alloc_size " + << "ignored for allocator_type='" << *cfg.allocator_type << "'" << std::endl; + } + + + if (!cfg.verbosity.has_value()) { + std::cerr << "[spla:validation] ERROR: required parameter missing: verbosity" << std::endl; + return ConfigStatus::MissedParameters; + } + if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { + std::cerr << "[spla:validation] ERROR: verbosity must be in [0, 3] (got " + << *cfg.verbosity << ")" << std::endl; + return ConfigStatus::InvalidConfigParams; + } + + return ConfigStatus::Ok; + } + + + ConfigStatus configure(int argc, char** argv) { + config_default.reset(); + config_system.reset(); + config_user.reset(); + config_explicit.reset(); + config_cli_meta = CliMeta{}; + config_cli_and_env.reset(); + config_final.reset(); + + ConfigStatus status; + + status = parse_cli_and_env(argc, argv, config_cli_meta, config_cli_and_env); + if (status != ConfigStatus::Ok) return status; + + std::string path; + + path = get_default_config_path(); + if (!std::filesystem::exists(path)) { + std::cerr << "[spla:configure] ERROR: default configuration file not found: " << path << std::endl; + return ConfigStatus::FileNotExists; + } + status = parse_file(path, config_default, true); + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] ERROR: cannot open default configuration file: " << path << std::endl; + return status; + } + if (status == ConfigStatus::ParseConfError) return status; + + + path = get_system_config_path(); + if (std::filesystem::exists(path)) { + status = parse_file(path, config_system, false); + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] ERROR: cannot open system configuration file: " << path << std::endl; + return status; + } + if (status == ConfigStatus::ParseConfError) return status; + } + + + path = get_user_config_path(); + if (std::filesystem::exists(path)) { + status = parse_file(path, config_user, false); + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] ERROR: cannot open user configuration file: " << path << std::endl; + return status; + } + if (status == ConfigStatus::ParseConfError) return status; + } + + + if (config_cli_meta.path_to_conf.has_value()) { + path = *config_cli_meta.path_to_conf; + if (!std::filesystem::exists(path)) { + std::cerr << "[spla:configure] ERROR: configuration file not found: " << path << std::endl; + return ConfigStatus::FileNotExists; + } + status = parse_file(path, config_explicit, false); + if (status == ConfigStatus::OpenFileError) { + std::cerr << "[spla:configure] ERROR: cannot open configuration file: " << path << std::endl; + return status; + } + if (status == ConfigStatus::ParseConfError) return status; + } + + ConfigFile merged; + merged.merge(config_default); + merged.merge(config_system); + merged.merge(config_user); + merged.merge(config_explicit); + + const std::string active = config_cli_meta.configuration.value_or("default"); + + status = apply_configuration(merged, active, config_final); + if (status != ConfigStatus::Ok) return status; + + config_final.merge(config_cli_and_env); + + status = validation(config_final); + if (status != ConfigStatus::Ok) return status; + + return ConfigStatus::Ok; + } + +}// namespace spla diff --git a/src/core/configure.hpp b/src/core/configure.hpp new file mode 100644 index 000000000..3604fe0b5 --- /dev/null +++ b/src/core/configure.hpp @@ -0,0 +1,106 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/SparseLinearAlgebra/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "CLI/CLI.hpp" +#include "cl_config_status.hpp" +#include + +#ifdef _WIN32 +#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) + #include + #include +#endif + +namespace spla { + + struct Configuration { + std::optional> extends; + + std::optional backend; + std::optional platform_index; + std::optional device_index; + std::optional if_gpu_unavailable; + + std::optional queues_count; + std::optional profiling; + std::optional allocator_type; + std::optional linear_alloc_size; + std::optional verbosity; + + void merge(const Configuration& source); + void reset(); + }; + + struct ConfigFile { + std::optional> configs; + + void merge(const ConfigFile& source); + void reset(); + }; + + struct CliMeta { + std::optional version; + std::optional configuration; + std::optional path_to_conf; + }; + + extern ConfigFile config_default; + extern ConfigFile config_system; + extern ConfigFile config_user; + extern ConfigFile config_explicit; + extern CliMeta config_cli_meta; + extern Configuration config_cli_and_env; + extern Configuration config_final; + + std::string get_spla_version(); + + std::string get_default_config_path(); + std::string get_system_config_path(); + std::string get_home_directory(); + std::string get_user_config_path(); + + ConfigStatus parse_cli_and_env(int argc, char** argv, CliMeta& meta, Configuration& cfg); + ConfigStatus parse_file(const std::string& path, ConfigFile& cfg, bool allow_default); + + Configuration apply_extends(const std::map& configs, + const std::string& name, + std::set& stack); + ConfigStatus apply_configuration(const ConfigFile& file, const std::string& name, Configuration& cfg); + + ConfigStatus validation(const Configuration& cfg); + + ConfigStatus configure(int argc, char** argv); + +}// namespace spla diff --git a/src/opencl/UserGuide.md b/src/opencl/UserGuide.md deleted file mode 100644 index fa774e23e..000000000 --- a/src/opencl/UserGuide.md +++ /dev/null @@ -1,473 +0,0 @@ -# User Guide - -Руководство по установке, проверке и настройке библиотеки spla. - -## Содержание - -1. [Установка](#установка) -2. [Проверка работоспособности](#проверка-работоспособности) -3. [Конфигурационный файл](#конфигурационный-файл) -4. [Настройка](#настройка) -5. [Конфигурации](#конфигурации) -6. [Наследование конфигураций (`extends`)](#наследование-конфигураций) - -## Установка - -Инструкции по установке см. в [README](https://github.com/SparseLinearAlgebra/spla#installation). - -## Проверка работоспособности - -После установки выполните команду, которая подтверждает, что библиотека готова к использованию. - -```bash -spla --softcheck -``` -Команда выполняет следующую последовательность действий: - -1. Читает конфигурационный файл, предоставляющийся библиотекой. -2. Инициализирует OpenCL, выбирает платформу и устройство. -4. Запускает простое тестовое задание. -5. Сообщает статус. - -Пример успешного вывода: -```bash -$ spla --softcheck -[spla:check] Starting sanity check... -[spla:check] Initializing OpenCL... -[spla:check] Selected platform: NVIDIA CUDA -[spla:check] Selected device: NVIDIA GeForce RTX 3080 -[spla:check] Running test kernel: 2 + 3 = ... -[spla:check] Result: 5 (expected 5) -[spla:check] SUCCESS - spla works correctly -``` - -## Конфигурационный файл -Конфигурационные файлы состоят из набора конфигураций, каждая конфигурация - это именованный набор параметров библиотеки, все параметры библиотеки описываются внутри конфигураций. - -### Параметры конфигурации -| Параметр | Тип | Описание | Допустимые значения | -| :--- | :--- | :--- | :--- | -| extends | array of string | Список конфигураций-родителей | имена конфигураций (со всех уровней) | -| backend | string | На каком устройстве работать | `"gpu"` - только GPU
`"cpu"` - только CPU
`"any"` - любое доступное устройство
`"by_index"` - выбрать по индексам ниже | -| platform_index | int | Индекс OpenCL платформы
Используются только при backend: `"by_index"`
При других значениях backend - игнорируются | ≥ 0 | -| device_index | int | Индекс устройства внутри платформы
Используются только при backend: `"by_index"`
При других значениях backend - игнорируются | ≥ 0 | -| if_gpu_unavailable | string | Что делать, если GPU недоступен
Не применяется при backend: `"cpu"` | `"use_cpu"` - переключиться на CPU
`"abort"` - вернуть ошибку
| -| queues_count | int | Число командных очередей | ≥ 1 | -| profiling | bool | Профилирование очередей | true, false | -| allocator_type | string | Тип аллокатора | `"general"`, `"linear"` | -| linear_alloc_size | int | Размер линейного аллокатора (байт)
Используются только при allocator_type: `"linear"` | ≥ 0 | -| verbosity | int | Уровень логирования | `0` - нет вывода,
`1` - только ошибки,
`2` - ошибки, предупреждения,
`3` - ошибки, предупреждения, дополнительная информация | - -Файл конфигурации, предоставляющийся библиотекой, имеет следующую структуру: -```json -{ - "default": { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu", - - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - - "verbosity": 2 - } -} -``` -## Настройка - -Если параметры по умолчанию вас не устраивают, вы можете настроить библиотеку. Способы конфигурирования перечислены в порядке убывания приоритета: - -1. Аргументы командной строки. -2. Переменные окружения. -3. Файл, путь к которому пользователь может задать явно. -- > При необходимости пользователь может явно указать файл с конфигурациями, который не находится по пути пользовательского и системного конфигурационного файла. -4. Пользовательский конфигурационный файл. -5. Системный конфигурационный файл. -6. Конфигурационный файл, поставляющийся библиотекой. - -### Расположение конфигурационных файлов - -**Конфигурационный файл с параметрами по умолчанию:** - ->Файл конфигурации с параметрами по умолчанию поставляется вместе с пакетом pyspla и располагается внутри директории установленного Python-пакета. -Расположение зависит от способа установки пакета (глобально, --user, в виртуальном окружении). - -**Системный конфигурационный файл:** ->Linux: `/etc/spla/spla_conf.json` \ -macOS: `/Library/Application Support/spla/spla_conf.json` \ -Windows: `%ProgramData%\spla\spla_conf.json` - -**Пользовательский конфигурационный файл:** ->Linux: `~/.config/spla/spla_conf.json` \ -macOS: `~/Library/Application Support/spla/spla_conf.json` \ -Windows: `%APPDATA%\spla\spla_conf.json` - -**Пользовательский конфигурационный файл, задавающийся явно:** - ->На усмотрение пользователя. - - -## Конфигурации - -Конфигурации позволяют хранить несколько наборов настроек в одном конфигурационном файле и переключаться между ними при запуске. Это удобно, когда одну и ту же программу нужно запускать в разных режимах. - -Если пользователь не укажет конфигурацию, то будет взята конфигурация `"default"` из файла, который идет с библиотекой. - -### Пример конфигурационного файла -```json -{ - "cpu": { - "backend": "cpu", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "verbosity": 2 - }, - - "gpu0": { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu", - "queues_count": 2, - "profiling": true, - "allocator_type": "linear", - "linear_alloc_size": 8, - "verbosity": 0 - }, - - "gpu1": { - "backend": "by_index", - "platform_index": 0, - "device_index": 2, - "if_gpu_unavailable": "abort", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "verbosity": 3 - } -} -``` -### Запуск -```bash -SPLA_CONFIG=cpu ./program -SPLA_CONFIG=gpu0 ./program -SPLA_CONFIG=gpu1 ./program -``` -Или через CLI: -```bash -./program --spla-config=gpu1 -``` -## Наследование конфигураций - -Иногда конфигурации пересекаются по смыслу - например, `debug_gpu1` должна включать и `режим отладки`, и `выбор GPU 1`. Чтобы не дублировать параметры, конфигурация может наследовать другие конфигурации через поле `extends`. - -Если конфигурация содержит поле `extends`, библиотека сначала применяет указанные в нём конфигурации по порядку. Параметры каждой родительской конфигурации применяются по очереди: последняя в списке переопределяет предыдущие. - -После этого применяются параметры самой выбранной конфигурации, которые переопределяют всё, что было задано раньше. -Если конфигурация не содержит `extends`, она полностью изолирована: применяются только её собственные параметры. - -### Примеры конфигурационных файлов - -``` json -{ - "gpu0": { - "backend": "by_index", - "platform_index": 0, - "device_index": 0, - "if_gpu_unavailable": "abort", - "queues_count": 1, - "profiling": false - }, - - "debug": { - "profiling": true, // будет переопределен конфигурацией "gpu0" - "allocator_type": "general", - "verbosity": 3 - }, - - "debug_gpu0": { - "extends": ["debug", "gpu0"] - } -} -``` -### Итоговый набор параметров - -| Параметр | Значение | Источник | -| :--- | :--- | :--- | -| backend | `by_index` | конфигурация `gpu0` | -| platform_index | `0` | конфигурация `gpu0` | -| device_index | `0` | конфигурация `gpu0` | -| if_gpu_unavailable | `"abort"` | конфигурация `gpu0` | -| queues_count | `1` | конфигурация `gpu0` | -| profiling | `false` | конфигурация `gpu0` | -| allocator_type | `general` | конфигурация `debug` | -| verbosity | `3` | конфигурация `debug` | -### Запуск -```bash -SPLA_CONFIG=debug_gpu0 ./program -``` -Или через CLI: -```bash -./program --spla-config=debug_gpu0 -``` ---- -```json -{ - "gpu0": { - "backend": "by_index", - "platform_index": 0, - "device_index": 0, - "if_gpu_unavailable": "abort", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "verbosity": 3 - }, - - "gpu0_profiling_true": { - "extends": ["gpu0"], - "profiling": true // переопределит "profiling": false конфигурации "gpu0" - } -} -``` -### Запуск -```bash -SPLA_CONFIG=gpu0_profiling_true ./program -``` -Или через CLI: -```bash -./program --spla-config=gpu0_profiling_true -``` -Конфигурационные файлы состоят из списка именованных конфигураций. Конфигурации из разных файлов (по умолчанию, системного, пользовательского, пользовательского с явно указанным путем) сливаются по именам: одноимённые конфигурации объединяются по параметрам, а уникальные добавляются. Итоговый набор используется для разрешения `extends` и выбора активной конфигурации. - -Имена в `extends` берутся из всех конфигураций, определённых в конфигурационгом файле по умолчанию, системном, пользовательском и пользовательском с явно указанным путем файлах конфигурации. Это позволяет наследовать конфигурации, определённые на другом уровне. Например, пользовательская конфигурация может наследовать `"default"` из файла по умолчанию, не дублируя его параметры. - -### Пример конфигурационного файла -Конфигурационный файл по умолчанию: -``` json -{ - "default": { - "backend": "gpu", // переопределится на "by_index" - "if_gpu_unavailable": "use_cpu", // переопределится на "abort" - - "queues_count": 1, - "profiling": false, // переопределится на true - "allocator_type": "general", - - "verbosity": 2 - } -} -``` -Конфигурационный файл, созданный пользователем: -```json -{ - "gpu0": { - "extends": ["default"], - "backend": "by_index", // переопределяет "backend": "gpu" - "platform_index": 0, - "device_index": 0, - "if_gpu_unavailable": "abort", // переопределяет "if_gpu_unavailable": "use_cpu" - "queues_count": 1, - "profiling": true - } -} -``` - -### Итоговый набор параметров - -| Параметр | Значение | Источник | -| :--- | :--- | :--- | -| backend | `by_index` | конфигурация `gpu0` | -| platform_index | `0` | конфигурация `gpu0` | -| device_index | `0` | конфигурация `gpu0` | -| if_gpu_unavailable | `"abort"` | конфигурация `gpu0` | -| queues_count | `1` | конфигурация `gpu0` | -| profiling | `true` | конфигурация `gpu0` | -| allocator_type | `general` | конфигурация по умолчанию | -| verbosity | `2` | конфигурация по умолчанию | - ---- ---- - -# Распространенные сценарии использования библиотеки - 1. Быстрый запуск без настройки. - 2. Выбор между CPU и GPU без указания индексов. - 3. Многократный запуск на разных устройствах с разными параметрами. - 4. Запуск с конфигурациями из произвольного файла. - -## Быстрый запуск без настройки - -Если вы хотите получить работоспособное приложение без настройки - ничего настраивать не нужно. Библиотека использует параметры по умолчанию из [конфигурационного файла](#конфигурационный-файл). Этот сценарий работает одинаково на Linux, macOS и Windows. Если GPU недоступен, библиотека автоматически переключится на CPU, сообщив об этом. \ -Перед первым запуском рекомендуется [выполнить](#проверка-работоспособности) `spla --softcheck`, чтобы убедиться, что всё необходимое для работы spla установлено. - -## Выбор между CPU и GPU без указания индексов - -Если вы хотите управлять типом устройства, но не указывать конкретные индексы OpenCL-платформ и устройств. - -### Управление через backend - -Тип устройства задаётся параметром backend -```json -{ - "gpu_only": { "backend": "gpu" }, // "gpu" - использовать первое доступное GPU; - "cpu_only": { "backend": "cpu" }, // "cpu" - использовать CPU; - "any": { "backend": "any" } // "any" - использовать первое доступное устройство любого типа. -} -``` - -Индексы `platform_index` и `device_index` при этих значениях игнорируются. - -### Поведение при отсутствии GPU - -Если выбран backend: `"gpu"`, но GPU недоступен, поведение определяется параметром `if_gpu_unavailable`: - -```json -{ - "gpu_or_cpu": { - "backend": "gpu", - "if_gpu_unavailable": "use_cpu" - }, - "gpu_only": { - "backend": "gpu", - "if_gpu_unavailable": "abort" - } -} -``` -`"use_cpu"` - библиотека переключается на CPU и продолжает работу. \ -`"abort"` - библиотека возвращает ошибку и не продолжает работу. \ -`if_gpu_unavailable` применяется только при backend: `"by_index"`, backend: `"gpu"` и backend: `"any"`. При backend: `"cpu"` параметр игнорируется. - -## Многократный запуск на разных устройствах с разными параметрами - -Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо того чтобы держать несколько файлов конфигурации, вы описываете всё в одном. -```json -{ - "default": { "backend": "gpu", "verbosity": 2 }, - - "gpu0": { - "extends": ["default"], - "backend": "by_index", - "platform_index": 0, - "device_index": 0 - }, - "gpu1": { - "extends": ["default"], - "backend": "by_index", - "platform_index": 0, - "device_index": 1 - }, - "gpu2": { - "extends": ["default"], - "backend": "by_index", - "platform_index": 0, - "device_index": 2 - }, - - "debug": { - "extends": ["default"], - "verbosity": 3, - "profiling": true - }, - "bench": { - "extends": ["default"], - "verbosity": 0 - }, - - "debug_gpu1": { "extends": ["debug", "gpu1"] }, - "bench_gpu2": { "extends": ["bench", "gpu2"] } -} -``` -Запуск -```bash -SPLA_CONFIG=gpu1 ./program -SPLA_CONFIG=debug ./program -SPLA_CONFIG=debug_gpu1 ./program -``` -Подробнее в главе про [конфигурации](#конфигурации) и [наследование конфигураций (`extends`)](#наследование-конфигураций). - -## Запуск ci с конфигурациями из произвольного файла - -Вам нужно запустить тесты в CI с отдельным файлом конфигурации. - -В среде CI неудобно и нежелательно трогать системный и пользовательский файлы конфигурации, а конфигурация тестов должна лежать в репозитории. Поэтому конфигурации описывают в отдельном файле внутри репозитория и указывают путь к нему при запуске и имя конфигурации. - -``` -my_project/ -├── .github/ -│ └── workflows/ -│ ├── ci_with_conf.yml -│ └── ci_spla_conf.json -├── src/ -└── tests/ -``` - -### ci_spla_conf.json -```json -{ - "test_cpu": { - "backend": "cpu", - "queues_count": 1, - "profiling": false, - "allocator_type": "general", - "verbosity": 1 - }, - "test_gpu0": { - "backend": "by_index", - "platform_index": 0, - "device_index": 0, - "if_gpu_unavailable": "abort", - "queues_count": 2, - "profiling": false, - "allocator_type": "general", - "verbosity": 0 - }, - "test_gpu1": { - "backend": "by_index", - "platform_index": 0, - "device_index": 1, - "if_gpu_unavailable": "abort", - "queues_count": 2, - "profiling": false, - "allocator_type": "linear", - "linear_alloc_size": 8, - "verbosity": 0 - } -} -``` - -### ci_with_conf.yml -```yml -name: CI - -on: [push, pull_request] - -jobs: - test: - name: Test (${{ matrix.config }}) - runs-on: [self-hosted] - - strategy: - fail-fast: false - matrix: - config: [test_cpu, test_gpu0, test_gpu1] - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install pyspla pytest - - - name: Run tests - env: - SPLA_CONFIG_FILE: ${{ github.workspace }}/.github/workflows/ci_spla_conf.json - SPLA_CONFIG: ${{ matrix.config }} - run: pytest tests/ -``` -Если пользователь не укажет конфигурацию, то будет взята конфигурация `"default"` из файла, который идет с библиотекой. \ No newline at end of file diff --git a/src/opencl/UserManual.md b/src/opencl/UserManual.md deleted file mode 100644 index 189983e9d..000000000 --- a/src/opencl/UserManual.md +++ /dev/null @@ -1,239 +0,0 @@ -# МАНУАЛ: - -## НАЗВАНИЕ -spla - это фреймворк для математических вычислений с использованием GPU/ускорения - - -## СИНОПСИС - -```cpp -#include - - -int main(int argc, char* argv[]) { - - configure(argc, argv); - - return 0; -} -``` -Функция `configure(argc, argv)` необходима для обработки аргументов командной строки, переменных окружения и конфигурационных файлов. - - -## ОПИСАНИЕ -**spla** - это библиотека с открытым исходным кодом, предоставляющая примитивы разреженной линейной алгебры (матрицы, векторы, скаляры) для математических вычислений с ускорением на GPU. Библиотека поддерживает широкий спектр операций, включая умножение матрицы на вектор, решение систем линейных уравнений и другие алгоритмы разреженной алгебры. - -Для большинства пользователей важно, на каком ускорителе будет запускаться их проект, поэтому необходима возможность явного указания графического ускорителя, OpenCL платформы, количества очередей команд и других параметров, влияющих на производительность и удобство пользователя. - -Библиотека предоставляет механизмы конфигурирования, показанные в порядке убывания приоритета. - -1. Аргументы командной строки 1. -2. Переменные окружения 2. -3. Пользовательский конфигурационный JSON файл 3. -4. Системный конфигурационный JSON файл 3. - -Системный конфигурационный файл имеет наименьший приоритет. \ -Его настройки переопределяются пользовательским конфигурационным файлом, переменными окружения и аргументами командной строки. - -Пользовательский конфигурационный файл имеет приоритет над системным -конфигурационным файлом. \ -Его настройки переопределяются переменными -окружения и аргументами командной строки. - -Переменные окружения имеют приоритет над системным и пользовательским конфигурационными файлами, но уступают аргументам командной строки. - -Аргументы командной строки имеют наивысший приоритет и переопределяют любые настройки, определенные предыдущими способами. - -Если источника конфигурации с меньшим приоритетом не существует, библиотека игнорирует его и переходит к следующему источнику конфигурации. - -Библиотека требует настройки всех обязательных параметров. Без этого будет генерироваться исключение `IncompleteConfigError`.\ -Чтобы исключение не возникало, пользователь должен явно настроить все параметры любым [способом](#configuration_methods). - -> 1 Описание аргументов командной строки приведены в разделе [ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ](#options). \ -2 Описание переменнных окружения приведены в разделе [ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ](#env_variables). \ -3 Шаблон конфигурационного файла с описанием приведен [здесь](#config). - -## ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ -```bash --sh ---spla-help -``` -Выводит список всех доступных флагов spla с кратким описанием. - -```bash --sv ---spla-version -``` -Показывает номер версии spla. - -```bash --ss <путь> ---spla-sconf <путь> -``` -Путь к системному конфигурационному файлу. - -По умолчанию ищет файл в стандартном для данной ОС месте.\ -`/etc/spla/` на Linux. \ -`/Library/Preferences/spla/` на macOS. \ -`%ProgramData%\spla\` на Windows. \ -По умолчанию выбирается первый json файл в соответствующей директории. - -```bash --su <путь> ---spla-uconf <путь> -``` -Путь к пользовательскому конфигурационному файлу. - -По умолчанию ищет файл в стандартном для данной ОС месте. \ -`~/.config/spla/` на Linux. \ -`~/Library/Application Support/spla/` на macOS. \ -`%APPDATA%\spla\` на Windows. \ -По умолчанию выбирается первый json файл в соответствующей директории. - -```bash --sp <индекс> ---spla-platform <индекс> -``` -Индекс OpenCL платформы. - -```bash --sd <индекс> ---spla-device <индекс> -``` -Индекс OpenCL-устройства выбранной платформы (GPU/CPU). - -```bash --sq <число> ---spla-queues <число> -``` -Количество очередей команд. - -Увеличение числа очередей может повысить производительность -за счет параллельного выполнения независимых задач, но слишком большое значение может снизить производительность из-за накладных расходов. \ -Рекомендуется начинать с 1 и экспериментально подбирать оптимальное значение. - -```bash --sV <уровень> ---spla-verbosity <уровень> -``` -Уровень детализации отладочной информации, выводимой библиотекой. - -| Уровень | Значение | Описание | -|:-------:|:---------|:---------| -| **0** | OFF | Вывод отключён. Сообщения не выводятся. | -| **1** | ERROR | Только критические ошибки. | -| **2** | WARNING | Ошибки и предупреждения. | -| **3** | INFO | Основные этапы работы библиотеки. | - -Что выводится на каждом уровне: - -1. ERROR — `Error`, `NoAcceleration`, `PlatformNotFound`, `DeviceNotFound`, `InvalidState`, `InvalidArgument`, `CompilationError` - -2. WARNING — добавляет к ERROR: `NoValue`, `NotImplemented` - -3. INFO — добавляет к WARNING: `Ok` - информация об инициализации, выборе платформы/устройства, загрузке конфигурации - -```bash --sp ---spla-profiling -``` -Профилирование очередей команд OpenCL. - -Bключение профилирования добавляет накладные расходы на каждую -операцию и может замедлить выполнение. - -```bash --sa <тип> ---spla-allocator <тип> -``` -Тип аллокатора памяти для OpenCL-устройства. \ -Ожидает: lineral | general. - -Выбор аллокатора влияет на производительность операций с памятью. -Линейный аллокатор даёт прирост скорости за счёт последовательного выделения, -но может привести к фрагментации памяти при длительной работе. -Общий аллокатор более надёжен, но медленнее. - -```bash --sS <размер> ---spla-allocator-size <размер> -``` -Размер линейного аллокатора в байтах. - -Увеличение размера позволяет выделять больше памяти за один раз, но увеличивает потребление ресурсов. \ -Этот параметр необходим только при использовании линейного аллокатора `--spla-allocator linear`. -При использовании общего аллокатора можно не указывать. - -Пример: -```bash -./my_program --spla-uconf ~/my_configs/spla.toml --spla-platform 1 -sd 0 --spla-verbosity 3 -sp true --spla-allocator linear --spla-allocator-size 1048576 -``` - -## ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ -Для всех параметров командной строки (кроме --spla-help, --spla-version) существуют аналоги в виде переменных окружения. - -`SPLA_SYSTEM_CONFIG_PATH` \ -Путь к системному конфигурационному файлу. Аналог параметра --spla-sconf. - -`SPLA_USER_CONFIG_PATH` \ -Путь к пользовательскому конфигурационному файлу. Аналог параметра --spla-uconf. - -`SPLA_OPENCL_PLATFORM` \ -Индекс OpenCL платформы. Аналог параметра --spla-platform. - -`SPLA_OPENCL_DEVICE`\ -Индекс OpenCL-устройства на выбранной платформе. -Аналог параметра --spla-device. - -`SPLA_QUEUES`\ -Количество очередей команд OpenCL. -Аналог параметра --spla-queues. - -`SPLA_VERBOSITY`\ -Уровень детализации отладочной информации. -Аналог параметра --spla-verbosity.\ -Принимает значения от 0 до 3. - -`SPLA_PROFILING`\ -Включает профилирование очередей команд OpenCL. -Аналог параметра --spla-profiling. - -`SPLA_ALLOCATOR`\ -Тип аллокатора памяти для OpenCL-устройства. -Аналог параметра --spla-allocator.\ -Принимает значения: linear, general. - -`SPLA_ALLOCATOR_SIZE`\ -Размер линейного аллокатора в байтах. -Аналог параметра --spla-allocator-size.\ -Имеет смысл только при использовании линейного аллокатора. - - -## КОНФИГУРАЦИОННЫЕ ФАЙЛЫ -Для всех аргументов командной строки (кроме --spla-help, --spla-version, --spla-sconf, --spla-uconf) и всех переменных окружения существуют аналоги в виде параметров конфигурационного файла. - -Формат файла - JSON. - -Типы значений. -1. platform = int -2. device = int -3. queues = int -4. verbosity = int -5. profiling = true | false -6. allocator = linear | general -7. allocator_size = int - -Примеры конфигурационных файлов.\ -Этот формат справедлив как для пользовательского, так и для системного конфигурационного json файла. - -```json -{ - "platform": 1, - "device": 0, - "queues": 4, - "verbosity": 2, - "profiling": false, - "allocator": "linear", - "allocator_size": 1048576 -} -``` \ No newline at end of file diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 0067ba881..938f404ac 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -27,9 +27,9 @@ #include "cl_accelerator.hpp" +#include #include #include -#include #include #include @@ -37,61 +37,100 @@ namespace spla { - CLAccelerator::CLAccelerator() = default; - CLAccelerator::~CLAccelerator() = default; - - InitResult init_with_configure(int argc, char** argv) { - InitResult result; - result.config_status = configure(argc, argv); - - if (result.config_status == ConfigStatus::VersionRequested) { - result.status = Status::Ok; - return result; + std::optional> find_first_device(cl_device_type type) { + std::vector platforms; +#if defined(CL_HPP_ENABLE_EXCEPTIONS) + try { + cl::Platform::get(&platforms); + } catch (const cl::Error& e) { + LOG_MSG(Status::PlatformNotFound, "failed to query OpenCL platforms: " << e.what()); + return std::nullopt; } - - if (result.config_status != ConfigStatus::Ok) { - result.status = Status::Error; - return result; +#else + cl::Platform::get(&platforms); +#endif + if (platforms.empty()) { + LOG_MSG(Status::PlatformNotFound, "no OpenCL platforms available"); + return std::nullopt; } - auto* acc = get_acc_cl(); - if (!acc) { - result.status = Status::NoAcceleration; - return result; + for (size_t p = 0; p < platforms.size(); p++) { + std::vector devices; +#if defined(CL_HPP_ENABLE_EXCEPTIONS) + try { + platforms[p].getDevices(type, &devices); + } catch (const cl::Error& e) { + LOG_MSG(Status::DeviceNotFound, "failed to query devices of platform " << p << ": " << e.what()); + continue; + } +#else + platforms[p].getDevices(type, &devices); +#endif + if (!devices.empty()) { + return std::make_pair(static_cast(p), 0); + } } - result.status = acc->init(); - return result; + return std::nullopt; } + CLAccelerator::CLAccelerator() = default; + CLAccelerator::~CLAccelerator() = default; Status CLAccelerator::init() { + if (!config_final.backend.has_value()) { + ConfigStatus status = configure(0, nullptr); + if (status != ConfigStatus::Ok) return Status::Error; + } std::string backend = config_final.backend.value(); int platform_index; int device_index; - if (backend == "by_index") { + int queues_count = config_final.queues_count.value(); + bool profiling = config_final.profiling.value(); + std::string allocator_type = config_final.allocator_type.value(); + size_t linear_alloc_size = config_final.linear_alloc_size.value_or(0); + int verbosity = config_final.verbosity.value(); + + Library::get()->set_verbosity(verbosity); + + if (backend == "cpu") { + auto found = find_first_device(CL_DEVICE_TYPE_CPU); + if (!found) { + LOG_MSG(Status::DeviceNotFound, "no OpenCL CPU device found (backend='cpu')"); + return Status::DeviceNotFound; + } + platform_index = found->first; + device_index = found->second; + + } else if (backend == "gpu" || backend == "any") { + auto found = find_first_device(CL_DEVICE_TYPE_GPU); + + if (!found && config_final.if_gpu_unavailable == "use_cpu") { + LOG_MSG(Status::Ok, "no OpenCL GPU device found, fallback to CPU (if_gpu_unavailable='use_cpu')"); + found = find_first_device(CL_DEVICE_TYPE_CPU); + } + + if (!found) { + LOG_MSG(Status::DeviceNotFound, "no OpenCL device found for backend='" << backend << "'"); + return Status::DeviceNotFound; + } + + platform_index = found->first; + device_index = found->second; + + } else if (backend == "by_index") { platform_index = config_final.platform_index.value(); device_index = config_final.device_index.value(); + } else { + LOG_MSG(Status::InvalidArgument, "unknown backend: " << backend); + return Status::InvalidArgument; } - std::string if_gpu_unavailable; - if (backend != "cpu") { - if_gpu_unavailable = config_final.if_gpu_unavailable.value(); - } - int queues_count = config_final.queues_count.value(); - bool profiling = config_final.profiling.value(); - std::string allocator_type = config_final.allocator_type.value(); - size_t linear_alloc_size; - if (allocator_type == "linear") { - linear_alloc_size = config_final.linear_alloc_size.value(); - } - int verbosity = config_final.verbosity.value(); - - Library::get()->set_verbosity(verbosity); LOG_MSG(Status::Ok, "Initializing accelerator..."); LOG_MSG(Status::Ok, "Configuration parameters:"); + LOG_MSG(Status::Ok, " backend = " << backend); LOG_MSG(Status::Ok, " platform = " << platform_index); LOG_MSG(Status::Ok, " device = " << device_index); LOG_MSG(Status::Ok, " queues = " << queues_count); @@ -102,16 +141,24 @@ namespace spla { } LOG_MSG(Status::Ok, " verbosity = " << verbosity); - set_platform(platform_index); - set_device(device_index); - set_profiling(profiling); - set_queues_count(queues_count); + Status status = set_platform(platform_index); + if (status != Status::Ok) return status; + + status = set_device(device_index); + if (status != Status::Ok) return status; + + status = set_profiling(profiling); + if (status != Status::Ok) return status; + + status = set_queues_count(queues_count); + if (status != Status::Ok) return status; if (allocator_type == "linear") { - set_linear_allocator(linear_alloc_size); + status = set_linear_allocator(linear_alloc_size); } else { - set_general_allocator(); + status = set_general_allocator(); } + if (status != Status::Ok) return status; m_cache = std::make_unique(); LOG_MSG(Status::Ok, "program cache created"); diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index 0790c5e5e..af9241441 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -36,7 +36,7 @@ #include #include -#include "cl_config_status.hpp" +#include #include #ifndef SPLA_RELEASE @@ -56,11 +56,6 @@ #define SPLA_OPENCL_DEVICE "SPLA_OPENCL_DEVICE" namespace spla { - struct InitResult { - Status status; - ConfigStatus config_status; - }; - InitResult init_with_configure(int argc, char** argv); /** * @addtogroup internal diff --git a/tools/soft_check.cpp b/tools/soft_check.cpp new file mode 100644 index 000000000..7b6e3610f --- /dev/null +++ b/tools/soft_check.cpp @@ -0,0 +1,154 @@ +/**********************************************************************************/ +/* This file is part of spla project */ +/* https://github.com/SparseLinearAlgebra/spla */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 SparseLinearAlgebra */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include +#include + +#include +#include +#include +#include + +namespace { + + constexpr const char* CHECK_TAG = "[spla:check]"; + + bool has_flag(int argc, char** argv, const char* flag) { + for (int i = 1; i < argc; ++i) { + if (std::strcmp(argv[i], flag) == 0) return true; + } + return false; + } + + spla_Status configure_without(int argc, char** argv, const char* flag) { + std::vector args; + args.reserve(static_cast(argc)); + + for (int i = 0; i < argc; ++i) { + if (i > 0 && std::strcmp(argv[i], flag) == 0) continue; + args.push_back(argv[i]); + } + + return spla_Configure(static_cast(args.size()), args.data()); + } + + void print_usage() { + std::cout << "spla - sparse linear algebra library\n\n" + << "Usage:\n" + << " spla --softcheck check that the environment is ready to work\n" + << " spla [options] apply configuration and exit\n\n" + << "Configuration options:\n" + << " --spla-config configuration to apply (default: \"default\")\n" + << " --spla-config-file explicitly specified configuration file\n" + << " --spla-backend gpu | cpu | any | by_index\n" + << " --spla-help show configuration help\n" + << " --spla-version show library version\n"; + } + + /** + * Runs a sanity check of the installed environment: + * 1. applies configuration (default config file, system/user files, env, cli); + * 2. initializes OpenCL and selects a platform and device; + * 3. runs a simple test task (2 + 3) and verifies the result. + * + * @return Exit code: 0 if everything is ready, 1 otherwise. + */ + int softcheck(int argc, char** argv) { + using namespace spla; + + std::cout << CHECK_TAG << " Starting sanity check..." << std::endl; + + if (configure_without(argc, argv, "--softcheck") != SPLA_STATUS_OK) { + std::cout << CHECK_TAG << " FAILED - invalid configuration" << std::endl; + return 1; + } + + std::cout << CHECK_TAG << " Initializing OpenCL..." << std::endl; + + Library::get()->set_default_callback(); + + if (Library::get()->set_accelerator(AcceleratorType::OpenCL) != Status::Ok) { + std::cout << CHECK_TAG << " FAILED - no OpenCL platform/device available" << std::endl; + return 1; + } + + std::string info; + Library::get()->get_accelerator_info(info); + std::cout << CHECK_TAG << " Selected accelerator: " << info << std::endl; + + auto a = Vector::make(1, INT); + auto b = Vector::make(1, INT); + auto c = Vector::make(1, INT); + + if (!a || !b || !c) { + std::cout << CHECK_TAG << " FAILED - cannot allocate test vectors" << std::endl; + return 1; + } + + a->set_int(0, 2); + b->set_int(0, 3); + + std::cout << CHECK_TAG << " Running test task: 2 + 3 = ..." << std::endl; + + if (exec_v_eadd(c, a, b, PLUS_INT) != Status::Ok) { + std::cout << CHECK_TAG << " FAILED - test task execution error" << std::endl; + return 1; + } + + T_INT result = 0; + c->get_int(0, result); + + std::cout << CHECK_TAG << " Result: " << result << " (expected 5)" << std::endl; + + if (result != 5) { + std::cout << CHECK_TAG << " FAILED - unexpected result" << std::endl; + return 1; + } + + Library::get()->finalize(); + std::cout << CHECK_TAG << " SUCCESS - spla works correctly" << std::endl; + return 0; + } + +}// namespace + +int main(int argc, char** argv) { + if (has_flag(argc, argv, "--softcheck")) { + return softcheck(argc, argv); + } + + const bool wants_help = has_flag(argc, argv, "--spla-help"); + const bool wants_version = has_flag(argc, argv, "--spla-version"); + + const spla_Status status = spla_Configure(argc, argv); + + if (wants_help || wants_version) return 0; + if (status != SPLA_STATUS_OK) return 1; + + print_usage(); + return 0; +} From ae1209da00457396f5c7768a33219f40088d33df Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 09:15:53 +0300 Subject: [PATCH 52/57] removed comment --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ee186967d..e358f7144 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,6 @@ if (SPLA_BUILD_OPENCL) set(OPENCL_ICD_LOADER_BUILD_TESTING OFF CACHE BOOL "" FORCE) add_subdirectory(deps/opencl-icd-loader) - # HPP bindings — из deps (только для Linux/Windows) message(STATUS "Add Khronos OpenCL HPP bindings") add_library(HeadersCpp INTERFACE) add_library(OpenCL::HeadersCpp ALIAS HeadersCpp) From 2b2448ee80b7891bbcb8b6b84d825722e1036399 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 09:44:11 +0300 Subject: [PATCH 53/57] fix for windows --- src/core/configure.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/configure.cpp b/src/core/configure.cpp index 36cc705f5..509f36500 100644 --- a/src/core/configure.cpp +++ b/src/core/configure.cpp @@ -91,11 +91,11 @@ namespace spla { std::string get_default_config_path() { #ifdef _WIN32 - HMODULE hModule; - GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - (LPCTSTR) &get_default_config_path, &hModule); + HMODULE hModule = nullptr; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, + reinterpret_cast(&get_default_config_path), &hModule); char path[MAX_PATH]; - GetModuleFileName(hModule, path, MAX_PATH); + GetModuleFileNameA(hModule, path, MAX_PATH); std::string dir = path; dir = dir.substr(0, dir.find_last_of("\\/")); return dir + "\\spla_conf.json"; From 66f1a3af1ab97f15ff4ec357b979e0bbd6bbf02f Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 11:48:42 +0300 Subject: [PATCH 54/57] deleted and renamed files --- ...cl_config_status.hpp => config_status.hpp} | 0 src/opencl/cl_config_status.hpp | 47 -- src/opencl/cl_configure.cpp | 564 ------------------ src/opencl/cl_configure.hpp | 115 ---- 4 files changed, 726 deletions(-) rename src/core/{cl_config_status.hpp => config_status.hpp} (100%) delete mode 100644 src/opencl/cl_config_status.hpp delete mode 100644 src/opencl/cl_configure.cpp delete mode 100644 src/opencl/cl_configure.hpp diff --git a/src/core/cl_config_status.hpp b/src/core/config_status.hpp similarity index 100% rename from src/core/cl_config_status.hpp rename to src/core/config_status.hpp diff --git a/src/opencl/cl_config_status.hpp b/src/opencl/cl_config_status.hpp deleted file mode 100644 index bfcd9dfab..000000000 --- a/src/opencl/cl_config_status.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/**********************************************************************************/ -/* This file is part of spla project */ -/* https://github.com/JetBrains-Research/spla */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 SparseLinearAlgebra */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - -#pragma once - -namespace spla { - - enum ConfigStatus { - Ok, - HelpRequested, - VersionRequested, - CliOrEnvParseError, - ParseConfError, - OpenFileError, - ProfileNotFound, - ProfileCycle, - MissedParameters, - PlatformNotFound, - DeviceNotFound, - InvalidConfigParams - }; - -}// namespace spla \ No newline at end of file diff --git a/src/opencl/cl_configure.cpp b/src/opencl/cl_configure.cpp deleted file mode 100644 index 72bac90c2..000000000 --- a/src/opencl/cl_configure.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/**********************************************************************************/ -/* This file is part of spla project */ -/* https://github.com/SparseLinearAlgebra/spla */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 SparseLinearAlgebra */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - -#include "cl_configure.hpp" -#include "cl_accelerator.hpp" - -#include -#include - -namespace spla { - - Config config_default; - Config config_system; - Config config_user; - Config config_cli_and_env; - Config config_final; - - - void Profile::merge(const Profile& src) { - if (src.backend.has_value()) backend = src.backend; - if (src.platform_index.has_value()) platform_index = src.platform_index; - if (src.device_index.has_value()) device_index = src.device_index; - if (src.if_gpu_unavailable.has_value()) if_gpu_unavailable = src.if_gpu_unavailable; - if (src.queues_count.has_value()) queues_count = src.queues_count; - if (src.profiling.has_value()) profiling = src.profiling; - if (src.allocator_type.has_value()) allocator_type = src.allocator_type; - if (src.linear_alloc_size.has_value()) linear_alloc_size = src.linear_alloc_size; - if (src.verbosity.has_value()) verbosity = src.verbosity; - if (src.extends.has_value()) extends = src.extends; - } - - - void Config::merge(const Config& src) { - if (src.backend.has_value()) backend = src.backend; - if (src.platform_index.has_value()) platform_index = src.platform_index; - if (src.device_index.has_value()) device_index = src.device_index; - if (src.if_gpu_unavailable.has_value()) if_gpu_unavailable = src.if_gpu_unavailable; - if (src.queues_count.has_value()) queues_count = src.queues_count; - if (src.profiling.has_value()) profiling = src.profiling; - if (src.allocator_type.has_value()) allocator_type = src.allocator_type; - if (src.linear_alloc_size.has_value()) linear_alloc_size = src.linear_alloc_size; - if (src.verbosity.has_value()) verbosity = src.verbosity; - - if (src.profile.has_value()) profile = src.profile; - - if (src.profiles.has_value()) { - if (!profiles.has_value()) { - profiles = src.profiles; - } else { - for (const auto& [name, src_prof] : *src.profiles) { - auto& dst_prof = (*profiles)[name]; - dst_prof.merge(src_prof); - } - } - } - } - - void Config::reset() { - *this = Config{}; - } - - std::string get_spla_version() { - return "SPLA version: 0.0.0"; - } - - - std::string get_default_config_path() { -#ifdef _WIN32 - if (const char* pd = std::getenv("PROGRAMDATA")) { - return std::string(pd) + "\\spla\\spla_conf.json"; - } - return "C:\\ProgramData\\spla\\spla_conf.json"; - -#elif defined(__APPLE__) - return "/usr/local/share/spla/spla_conf.json"; - -#elif defined(__linux__) - return "/usr/share/spla/spla_conf.json"; - -#else - #error "spla supports only Windows, macOS and Linux" -#endif - } - - - std::string get_default_system_config_path() { -#ifdef _WIN32 - const char* program_data = std::getenv("PROGRAMDATA"); - if (program_data) { - return std::string(program_data) + "\\spla\\spla_conf.json"; - } - return "C:\\ProgramData\\spla\\spla_conf.json"; - -#elif defined(__APPLE__) - return "/Library/Application Support/spla/spla_conf.json"; - -#elif defined(__linux__) - return "/etc/spla/spla_conf.json"; - -#else - #error "spla supports only Windows, macOS and Linux" -#endif - } - - - std::string get_home_directory() { -#ifdef _WIN32 - const char* home = std::getenv("USERPROFILE"); - if (home) return std::string(home); - - const char* drive = std::getenv("HOMEDRIVE"); - const char* path = std::getenv("HOMEPATH"); - if (drive && path) return std::string(drive) + std::string(path); - throw std::runtime_error("Cannot determine home directory"); - -#elif defined(__APPLE__) || defined(__linux__) - const char* home = std::getenv("HOME"); - if (home) return std::string(home); - - struct passwd* pw = getpwuid(getuid()); - if (pw) return std::string(pw->pw_dir); - throw std::runtime_error("Cannot determine home directory"); - -#else - #error "spla supports only Windows, macOS and Linux" -#endif - } - - - std::string get_default_user_config_path() { - std::string home = get_home_directory(); - -#ifdef _WIN32 - const char* app_data = std::getenv("APPDATA"); - if (app_data) return std::string(app_data) + "\\spla\\spla_conf.json"; - return home + "\\AppData\\Roaming\\spla\\spla_conf.json"; - -#elif defined(__APPLE__) - return home + "/Library/Application Support/spla/spla_conf.json"; - -#elif defined(__linux__) || defined(__unix__) - return home + "/.config/spla/spla_conf.json"; - -#else - #error "spla supports only Windows, macOS and Linux" -#endif - } - - - ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg) { - CLI::App app{"SPLA configuration"}; - - app.set_help_flag("-sh,--spla-help", "Show help and exit"); - app.add_flag("-sv,--spla-version", cfg.version, "Show version and exit"); - - app.add_option("-sb,--spla-backend", cfg.backend, - "Device type to use:\n" - " gpu - only GPU\n" - " cpu - only CPU\n" - " any - any available device\n" - " by_index - select by platform_index and device_index\n" - "Config key: backend") - ->envname("SPLA_BACKEND"); - - app.add_option("-sp,--spla-platform-index", cfg.platform_index, - "OpenCL platform index\n" - "Used only with backend=by_index.\n" - "Config key: platform_index") - ->envname("SPLA_PLATFORM_INDEX"); - - app.add_option("-sd,--spla-device-index", cfg.device_index, - "OpenCL device index\n" - "Used only with backend=by_index.\n" - "Config key: device_index") - ->envname("SPLA_DEVICE_INDEX"); - - app.add_option("-sf,--spla-if-gpu-unavailable", cfg.if_gpu_unavailable, - "Behavior when GPU is unavailable:\n" - " use_cpu - switch to CPU\n" - " abort - return error\n" - "Config key: if_gpu_unavailable") - ->envname("SPLA_IF_GPU_UNAVAILABLE"); - - app.add_option("-sq,--spla-queues-count", cfg.queues_count, - "Number of command queues\n" - "Config key: queues_count") - ->envname("SPLA_QUEUES_COUNT"); - - app.add_flag("-pr,--spla-profiling", cfg.profiling, - "Enable profiling of command queues\n" - "Config key: profiling") - ->envname("SPLA_PROFILING"); - - app.add_option("-sa,--spla-allocator-type", cfg.allocator_type, - "Allocator type:\n" - " general\n" - " linear \n" - "Config key: allocator_type") - ->envname("SPLA_ALLOCATOR_TYPE"); - - app.add_option("-as,--spla-linear-alloc-size", cfg.linear_alloc_size, - "Linear allocator size in bytes\n" - "Required for allocator_type=linear. Ignored for general.\n" - "Config key: linear_alloc_size") - ->envname("SPLA_LINEAR_ALLOC_SIZE"); - - app.add_option("-sV,--spla-verbosity", cfg.verbosity, - "Verbosity level:\n" - " 0 - no output\n" - " 1 - errors only\n" - " 2 - errors and warnings\n" - " 3 - all messages\n" - "Config key: verbosity") - ->envname("SPLA_VERBOSITY"); - - app.add_option("-sP,--spla-profile", cfg.profile, - "Configuration profile name\n" - "Overrides base settings with the named profile.\n" - "Config key: profile") - ->envname("SPLA_PROFILE"); - - try { - app.parse(argc, argv); - } catch (const CLI::ParseError& e) { - std::cerr << "[spla:cli_env] ERROR: failed to parse: " << e.what() << std::endl; - return ConfigStatus::CliOrEnvParseError; - } - - if (cfg.version) { - std::cout << get_spla_version() << std::endl; - return ConfigStatus::VersionRequested; - } - - return ConfigStatus::Ok; - } - - - ConfigStatus parse_file(const std::string& path, Config& cfg) { - - if (!std::filesystem::exists(path)) { - std::cerr << "[spla:config] WARNING: file not found: " << path << std::endl; - return ConfigStatus::Ok; - } - - std::ifstream file(path); - if (!file.is_open()) { - std::cerr << "[spla:config] WARNING: cannot open: " << path << std::endl; - return ConfigStatus::OpenFileError; - } - - try { - nlohmann::json data = nlohmann::json::parse(file); - - if (data.contains("backend")) cfg.backend = data["backend"].get(); - - if (data.contains("platform_index")) cfg.platform_index = data["platform_index"].get(); - if (data.contains("device_index")) cfg.device_index = data["device_index"].get(); - - if (data.contains("if_gpu_unavailable")) cfg.if_gpu_unavailable = data["if_gpu_unavailable"].get(); - - if (data.contains("queues_count")) cfg.queues_count = data["queues_count"].get(); - if (data.contains("profiling")) cfg.profiling = data["profiling"].get(); - if (data.contains("allocator_type")) cfg.allocator_type = data["allocator_type"].get(); - if (data.contains("linear_alloc_size")) cfg.linear_alloc_size = data["linear_alloc_size"].get(); - - if (data.contains("verbosity")) cfg.verbosity = data["verbosity"].get(); - - if (data.contains("profile")) cfg.profile = data["profile"].get(); - - if (data.contains("profiles")) { - std::map profiles; - for (auto& [name, p] : data["profiles"].items()) { - Profile prof; - - if (p.contains("backend")) prof.backend = p["backend"].get(); - - if (p.contains("platform_index")) prof.platform_index = p["platform_index"].get(); - if (p.contains("device_index")) prof.device_index = p["device_index"].get(); - - if (p.contains("if_gpu_unavailable")) prof.if_gpu_unavailable = p["if_gpu_unavailable"].get(); - - if (p.contains("queues_count")) prof.queues_count = p["queues_count"].get(); - if (p.contains("profiling")) prof.profiling = p["profiling"].get(); - if (p.contains("allocator_type")) prof.allocator_type = p["allocator_type"].get(); - if (p.contains("linear_alloc_size")) prof.linear_alloc_size = p["linear_alloc_size"].get(); - - if (p.contains("verbosity")) prof.verbosity = p["verbosity"].get(); - - if (p.contains("extends")) prof.extends = p["extends"].get>(); - - profiles[name] = prof; - } - cfg.profiles = profiles; - } - - return ConfigStatus::Ok; - - } catch (const nlohmann::json::exception& e) { - std::cerr << "[spla:config] ERROR: failed to parse '" - << path << "': " << e.what() << std::endl; - return ConfigStatus::ParseConfError; - } - } - - - ConfigStatus validation(const Config& cfg) { - if (!cfg.backend.has_value()) { - std::cerr << "[spla:validation] ERROR: required parameter missing: backend" << std::endl; - return ConfigStatus::MissedParameters; - } - - const std::string& backend = *cfg.backend; - if (backend != "gpu" && backend != "cpu" && - backend != "any" && backend != "by_index") { - std::cerr << "[spla:validation] ERROR: backend must be " - << "'gpu', 'cpu', 'any' or 'by_index' (got '" << backend << "')" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - if (backend == "by_index") { - if (!cfg.platform_index.has_value()) { - std::cerr << "[spla:validation] ERROR: platform_index is required " - << "when backend='by_index'" << std::endl; - return ConfigStatus::MissedParameters; - } - if (!cfg.device_index.has_value()) { - std::cerr << "[spla:validation] ERROR: device_index is required " - << "when backend='by_index'" << std::endl; - return ConfigStatus::MissedParameters; - } - - if (cfg.platform_index < 0) { - std::cerr << "[spla:opencl] ERROR: platform must be >= 0 (got " - << *cfg.platform_index << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - if (cfg.device_index < 0) { - std::cerr << "[spla:opencl] ERROR: device must be >= 0 (got " - << *cfg.device_index << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - } - - if (backend != "cpu") { - if (!cfg.if_gpu_unavailable.has_value()) { - std::cerr << "[spla:validation] ERROR: if_gpu_unavailable is required " - << "when backend= 'any', 'gpu', 'by_index'" << std::endl; - return ConfigStatus::MissedParameters; - } - const std::string& behavior = *cfg.if_gpu_unavailable; - if (behavior != "use_cpu" && behavior != "abort") { - std::cerr << "[spla:validation] ERROR: if_gpu_unavailable must be " - << "'use_cpu' or 'abort' (got '" << behavior << "')" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - } - if (backend == "cpu" && cfg.if_gpu_unavailable.has_value()) { - std::cerr << "[spla:validation] WARNING: if_gpu_unavailable " - << "ignored for backend='" << backend << "'" << std::endl; - } - - - if (backend != "by_index") { - if (cfg.platform_index.has_value() || cfg.device_index.has_value()) { - std::cerr << "[spla:validation] WARNING: platform_index/device_index " - << "ignored for backend='" << backend << "'" << std::endl; - } - } - - - if (!cfg.queues_count.has_value()) { - std::cerr << "[spla:validation] ERROR: required parameter missing: queues_count" << std::endl; - return ConfigStatus::MissedParameters; - } - if (*cfg.queues_count <= 0) { - std::cerr << "[spla:validation] ERROR: queues_count must be > 0 (got " - << *cfg.queues_count << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - - if (!cfg.profiling.has_value()) { - std::cerr << "[spla:validation] ERROR: required parameter missing: profiling" << std::endl; - return ConfigStatus::MissedParameters; - } - - - if (!cfg.allocator_type.has_value()) { - std::cerr << "[spla:validation] ERROR: required parameter missing: allocator_type" << std::endl; - return ConfigStatus::MissedParameters; - } - if (*cfg.allocator_type != "general" && *cfg.allocator_type != "linear") { - std::cerr << "[spla:validation] ERROR: allocator_type must be " - << "'general' or 'linear' (got '" << *cfg.allocator_type << "')" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - - if (*cfg.allocator_type == "linear") { - if (!cfg.linear_alloc_size.has_value()) { - std::cerr << "[spla:validation] ERROR: linear_alloc_size is required " - << "when allocator_type='linear'" << std::endl; - return ConfigStatus::MissedParameters; - } - if (*cfg.linear_alloc_size <= 0) { - std::cerr << "[spla:validation] ERROR: linear_alloc_size must be > 0 (got " - << *cfg.linear_alloc_size << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - } - - - if (!cfg.verbosity.has_value()) { - std::cerr << "[spla:validation] ERROR: required parameter missing: verbosity" << std::endl; - return ConfigStatus::MissedParameters; - } - if (*cfg.verbosity < 0 || *cfg.verbosity > 3) { - std::cerr << "[spla:validation] ERROR: verbosity must be in [0, 3] (got " - << *cfg.verbosity << ")" << std::endl; - return ConfigStatus::InvalidConfigParams; - } - - return ConfigStatus::Ok; - } - - - Profile apply_extends(const std::map& profiles, - const std::string& name, - std::set& stack) { - if (stack.count(name)) { - throw std::runtime_error("Profile cycle detected: " + name); - } - stack.insert(name); - - auto it = profiles.find(name); - if (it == profiles.end()) { - throw std::runtime_error("Profile not found: " + name); - } - - const Profile& prof = it->second; - Profile result; - - if (prof.extends) { - for (const auto& parent_name : *prof.extends) { - Profile parent = apply_extends(profiles, parent_name, stack); - result.merge(parent); - } - } - - result.merge(prof); - - stack.erase(name); - return result; - } - - ConfigStatus apply_profile(Config& cfg) { - - if (!cfg.profile.has_value()) return ConfigStatus::Ok; - - std::string profile_name = *cfg.profile; - - if (!cfg.profiles || !cfg.profiles->count(profile_name)) { - std::cerr << "[spla:profile] ERROR: not found: " << profile_name << std::endl; - return ConfigStatus::ProfileNotFound; - } - - std::set stack; - Profile resolved; - try { - resolved = apply_extends(*cfg.profiles, profile_name, stack); - } catch (const std::runtime_error& e) { - std::string msg = e.what(); - if (msg.find("cycle") != std::string::npos) { - std::cerr << "[spla:profile] ERROR: cycle detected: " - << profile_name << std::endl; - return ConfigStatus::ProfileCycle; - } - std::cerr << "[spla:profile] ERROR: " << msg << std::endl; - return ConfigStatus::ProfileNotFound; - } - - if (resolved.backend) cfg.backend = resolved.backend; - if (resolved.if_gpu_unavailable) cfg.if_gpu_unavailable = resolved.if_gpu_unavailable; - if (resolved.platform_index) cfg.platform_index = resolved.platform_index; - if (resolved.device_index) cfg.device_index = resolved.device_index; - if (resolved.queues_count) cfg.queues_count = resolved.queues_count; - if (resolved.profiling) cfg.profiling = resolved.profiling; - if (resolved.allocator_type) cfg.allocator_type = resolved.allocator_type; - if (resolved.linear_alloc_size) cfg.linear_alloc_size = resolved.linear_alloc_size; - if (resolved.verbosity) cfg.verbosity = resolved.verbosity; - - return ConfigStatus::Ok; - } - - - ConfigStatus configure(int argc, char** argv) { - config_default.reset(); - config_system.reset(); - config_user.reset(); - config_cli_and_env.reset(); - config_final.reset(); - - ConfigStatus status; - - status = parse_cli_and_env(argc, argv, config_cli_and_env); - if (status != ConfigStatus::Ok) return status; - - status = parse_file(get_default_user_config_path(), config_user); - if (status == ConfigStatus::ParseConfError) return status; - if (status == ConfigStatus::OpenFileError) { - std::cerr << "[spla:configure] WARNING: cannot open user config, skipping" << std::endl; - } - - status = parse_file(get_default_system_config_path(), config_system); - if (status == ConfigStatus::ParseConfError) return status; - if (status == ConfigStatus::OpenFileError) { - std::cerr << "[spla:configure] WARNING: cannot open system config, skipping" << std::endl; - } - - status = parse_file(get_default_config_path(), config_default); - if (status == ConfigStatus::ParseConfError) return status; - if (status == ConfigStatus::OpenFileError) { - std::cerr << "[spla:configure] WARNING: cannot open default config, skipping" << std::endl; - } - - config_final.merge(config_default); - config_final.merge(config_system); - config_final.merge(config_user); - config_final.merge(config_cli_and_env); - - status = apply_profile(config_final); - if (status != ConfigStatus::Ok) return status; - - status = validation(config_final); - if (status != ConfigStatus::Ok) return status; - - std::cerr << "[spla:configure]: configuration complete" << std::endl; - return ConfigStatus::Ok; - } -}// namespace spla diff --git a/src/opencl/cl_configure.hpp b/src/opencl/cl_configure.hpp deleted file mode 100644 index a51200801..000000000 --- a/src/opencl/cl_configure.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/**********************************************************************************/ -/* This file is part of spla project */ -/* https://github.com/SparseLinearAlgebra/spla */ -/**********************************************************************************/ -/* MIT License */ -/* */ -/* Copyright (c) 2023 SparseLinearAlgebra */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining a copy */ -/* of this software and associated documentation files (the "Software"), to deal */ -/* in the Software without restriction, including without limitation the rights */ -/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ -/* copies of the Software, and to permit persons to whom the Software is */ -/* furnished to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be included in all */ -/* copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ -/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ -/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ -/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ -/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ -/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ -/* SOFTWARE. */ -/**********************************************************************************/ - -#pragma once - -#include -#include -#include -#include -#include - -#include "CLI/CLI.hpp" -#include "cl_config_status.hpp" -#include - -#ifdef _WIN32 -#elif defined(__APPLE__) || defined(__linux__) || defined(__unix__) - #include - #include -#endif - -namespace spla { - - struct Profile { - std::optional backend; - - std::optional platform_index; - std::optional device_index; - - std::optional if_gpu_unavailable; - - std::optional queues_count; - std::optional profiling; - std::optional allocator_type; - std::optional linear_alloc_size; - std::optional verbosity; - std::optional> extends; - - void merge(const Profile& source); - }; - - struct Config { - std::optional version; - - std::optional backend; - - std::optional platform_index; - std::optional device_index; - - std::optional if_gpu_unavailable; - - std::optional queues_count; - std::optional profiling; - std::optional allocator_type; - std::optional linear_alloc_size; - std::optional verbosity; - - std::optional profile; - std::optional> profiles; - - void merge(const Config& source); - void reset(); - }; - - - extern Config config_default; - extern Config config_system; - extern Config config_user; - extern Config config_cli_and_env; - extern Config config_final; - - std::string get_spla_version(); - - std::string get_default_config_path(); - std::string get_default_system_config_path(); - std::string get_home_directory(); - std::string get_default_user_config_path(); - - ConfigStatus parse_cli_and_env(int argc, char** argv, Config& cfg); - ConfigStatus parse_file(const std::string& path, Config& cfg); - - ConfigStatus validation(const Config& cfg); - - Profile apply_extends(const std::map& profiles, - const std::string& name, - std::set& stack); - ConfigStatus apply_profile(Config& cfg); - - ConfigStatus configure(int argc, char** argv); - -}// namespace spla \ No newline at end of file From 14c6bf1bfba82d473c91f1038149d84412e1d9d6 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 11:56:35 +0300 Subject: [PATCH 55/57] cl_config_status.hpp -> config_status.hpp --- CMakeLists.txt | 2 +- src/binding/c_config.hpp | 2 +- src/core/configure.hpp | 2 +- src/opencl/cl_accelerator.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e358f7144..7e24a342d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -329,7 +329,7 @@ add_library(spla SHARED include/spla/vector.hpp src/core/accelerator.hpp src/core/common.hpp - src/core/cl_config_status.hpp + src/core/config_status.hpp src/core/configure.cpp src/core/configure.hpp src/core/dispatcher.cpp diff --git a/src/binding/c_config.hpp b/src/binding/c_config.hpp index 2a89e2514..4dbc96e5b 100644 --- a/src/binding/c_config.hpp +++ b/src/binding/c_config.hpp @@ -28,7 +28,7 @@ #ifndef SPLA_C_CONFIG_HPP #define SPLA_C_CONFIG_HPP -#include +#include #include #include diff --git a/src/core/configure.hpp b/src/core/configure.hpp index 3604fe0b5..f0e5d5cb5 100644 --- a/src/core/configure.hpp +++ b/src/core/configure.hpp @@ -34,7 +34,7 @@ #include #include "CLI/CLI.hpp" -#include "cl_config_status.hpp" +#include "config_status.hpp" #include #ifdef _WIN32 diff --git a/src/opencl/cl_accelerator.hpp b/src/opencl/cl_accelerator.hpp index af9241441..13fd731e0 100644 --- a/src/opencl/cl_accelerator.hpp +++ b/src/opencl/cl_accelerator.hpp @@ -36,7 +36,7 @@ #include #include -#include +#include #include #ifndef SPLA_RELEASE From e31094b2d3be570dae65bb120c617f4cf5ae46b0 Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 13:48:24 +0300 Subject: [PATCH 56/57] chanjed ci back --- .github/workflows/self-hosted.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- src/opencl/cl_accelerator.cpp | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/self-hosted.yml b/.github/workflows/self-hosted.yml index 5b6958d31..b15d036e5 100644 --- a/.github/workflows/self-hosted.yml +++ b/.github/workflows/self-hosted.yml @@ -90,7 +90,7 @@ jobs: - name: Check for tests results run: | - ! grep -qE "\[ FAILED \]" ${{ env.test-file }} + ! grep -qi "FAILED" ${{ env.test-file }} clean: name: Cleanup workspace diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 60c9bdd55..6828c3d40 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -106,4 +106,4 @@ jobs: - name: Check for tests results run: | - ! grep -qE "\[ FAILED \]" ${{ env.test-file }} + ! grep -qi "FAILED" ${{ env.test-file }} diff --git a/src/opencl/cl_accelerator.cpp b/src/opencl/cl_accelerator.cpp index 938f404ac..6e5dd2ea9 100644 --- a/src/opencl/cl_accelerator.cpp +++ b/src/opencl/cl_accelerator.cpp @@ -83,14 +83,14 @@ namespace spla { if (status != ConfigStatus::Ok) return Status::Error; } - std::string backend = config_final.backend.value(); + std::string backend = config_final.backend.value_or("gpu"); int platform_index; int device_index; - int queues_count = config_final.queues_count.value(); - bool profiling = config_final.profiling.value(); - std::string allocator_type = config_final.allocator_type.value(); + int queues_count = config_final.queues_count.value_or(1); + bool profiling = config_final.profiling.value_or(false); + std::string allocator_type = config_final.allocator_type.value_or("general"); size_t linear_alloc_size = config_final.linear_alloc_size.value_or(0); - int verbosity = config_final.verbosity.value(); + int verbosity = config_final.verbosity.value_or(2); Library::get()->set_verbosity(verbosity); From 0a82109b4f6cde1efc0fb6a6046d8be0bc6d295f Mon Sep 17 00:00:00 2001 From: Gitubrr Date: Tue, 13 Oct 2026 13:56:04 +0300 Subject: [PATCH 57/57] chanjed lang to english --- docs/LibsCompare.md | 152 +++++++++++----------- docs/UserGuide.md | 116 ++++++++--------- docs/UserManual.md | 310 ++++++++++++++++++++++---------------------- 3 files changed, 289 insertions(+), 289 deletions(-) diff --git a/docs/LibsCompare.md b/docs/LibsCompare.md index 3001d1ae7..75bc4cb95 100644 --- a/docs/LibsCompare.md +++ b/docs/LibsCompare.md @@ -1,106 +1,106 @@ -# Сравнение библиотек для создания механизма конфигурирования -Вся информация взята из репозиториев соответствующих проектов. Дата обращения: 21.04.26. +# Comparison of libraries for creating a configuration mechanism +All information is taken from the repositories of the corresponding projects. Access date: 21.04.26. -## Критерии сравнения +## Comparison criteria -| Критерий | Метрика | Единицы измерения | +| Criterion | Metric | Units | |:---|:---|:---| -| **Зависимости** | наличие | +/- | -| **Источники** | CLI (argv) / env / файлы | +/-, форматы | -| **Стандарт C++** | минимальная версия | C++хх | -| **Поддерживает стандарт иерархии** | Linux/Windows/MacOS | +/- | -| **Способ распространения** | header-only / статическая / динамическая | - | -| **ОС** | Linux / Windows / macOS | +/-, компиляторы | -| **Активность** | среднее число коммитов | коммитов/мес (за последний мес) | -| **Issues** | open, closed/open | n, коэффициент | -| **Сообщество** | GitHub Stars | n | -| **Проходит ли CI** | CI | +/- | +| **Dependencies** | presence | +/- | +| **Sources** | CLI (argv) / env / files | +/-, formats | +| **C++ standard** | minimum version | C++xx | +| **Supports standard hierarchy** | Linux/Windows/MacOS | +/- | +| **Distribution** | header-only / static / dynamic | - | +| **OS** | Linux / Windows / macOS | +/-, compilers | +| **Activity** | average number of commits | commits/month (last month) | +| **Issues** | open, closed/open | n, ratio | +| **Community** | GitHub Stars | n | +| **Passes CI** | CI | +/- | -> ? - не указано в README. +> ? - not specified in the README. -## Сравнение парсеров командной строки (CLI) +## Comparison of command line parsers (CLI) -| Критерий | CLI11 | cxxopts | +| Criterion | CLI11 | cxxopts | |:---|:---:|:---:| -| Зависимости | - | - | -| **Источники** | | | -|  CLI (argv) | + | + | -|  env | + | - | -|  Файлы | - | - | -| Стандарт C++ | ≥ C++11 | ≥ C++11 | -| **Поддерживает стандарт иерархии** | | | +| Dependencies | - | - | +| **Sources** | | | +|  CLI (argv) | + | + | +|  env | + | - | +|  Files | - | - | +| C++ standard | ≥ C++11 | ≥ C++11 | +| **Supports standard hierarchy** | | | |  Linux | + | + | -|  Windows | + | + | -|  MacOS | + | + | -| Способ распространения | header-only | header-only -| **ОС** | | | -|  Linux | + (GCC 4.8+, Clang 3.5+) | + (GCC ≥ 4.9, Clang ≥ 3.1) | -|  Windows | + (MSVC ≥ 2015) | + (MSVC ≥ 2015) | -|  macOS | + (AppleClang 7+) | + (Clang ≥ 3.1 с libc++) | -| **Сообщество** | | | -|  Активность (коммитов/мес) | 4 | 1 | -|  Issues всего | 506 | 307 | -|  Issues closed/open | 9 | 6 | -|  Stars | 4.3k | 4.7k | -| Проходит ли CI | + | + | + | - - -## Парсеры файлов - -| Критерий | nlohmann/json | yaml-cpp | toml++ | toml11 | config-cxx | taocpp/config +|  Windows | + | + | +|  MacOS | + | + | +| Distribution | header-only | header-only +| **OS** | | | +|  Linux | + (GCC 4.8+, Clang 3.5+) | + (GCC ≥ 4.9, Clang ≥ 3.1) | +|  Windows | + (MSVC ≥ 2015) | + (MSVC ≥ 2015) | +|  macOS | + (AppleClang 7+) | + (Clang ≥ 3.1 with libc++) | +| **Community** | | | +|  Activity (commits/month) | 4 | 1 | +|  Total issues | 506 | 307 | +|  Issues closed/open | 9 | 6 | +|  Stars | 4.3k | 4.7k | +| Passes CI | + | + | + | + + +## File parsers + +| Criterion | nlohmann/json | yaml-cpp | toml++ | toml11 | config-cxx | taocpp/config |:---|:---:|:---:|:---:|:---:|:---:|:---:| -| Зависимости | - | - | - | - | - | - | -| **Источники** | +| Dependencies | - | - | - | - | - | - | +| **Sources** | |  CLI (argv) | - | - | - | - | - | - | |  env | - | - | - | - | + | + | -|  Файлы | JSON | YAML | TOML | TOML | JSON, YAML, XML | JSON, JAXN | -| Стандарт C++ | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 | ≥ C++20 | ≥ C++17 | -| **Поддерживает стандарт иерархии** | +|  Files | JSON | YAML | TOML | TOML | JSON, YAML, XML | JSON, JAXN | +| C++ standard | ≥ C++11 | ≥ C++11 | ≥ C++17 | ≥ C++11 | ≥ C++20 | ≥ C++17 | +| **Supports standard hierarchy** | |  Linux | + | + | + | + | + | + | |  Windows | + | + | + | + | + | + | |  MacOS | + | + | + | + | + | + | -| Способ распространения | header-only | статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only/статическая/динамическая¹ | header-only | header-only | -| **ОС** | | | +| Distribution | header-only | static/dynamic¹ | header-only/static/dynamic¹ | header-only/static/dynamic¹ | header-only | header-only | +| **OS** | | | |  Linux | + (GCC 4.8–14.2, Clang 3.4–21.0) | + (GCC, Clang) | + (Clang 8+, GCC 8+) | + (GCC, Clang) | + (GCC 13+, Clang 16+) | + |  Windows | + (MSVC 2015–2022) | + (MSVC) | + (MSVC VS2019+) | + (MSVC, MinGW) | + (MSVC 143+ (VS 2022)) | + |  macOS | + (AppleClang 9.1–16.0) | + (Xcode, AppleClang) | + (AppleClang) | + (AppleClang) | + (AppleClang 16+) | + -| **Сообщество** | | | -|  Активность (коммитов/мес) | 2 | 9 | 2 | 4 | 2 | 13 | -|  Issues всего | 3271 | 905 | 193 | 194 | 24 | 5 | +| **Community** | | | +|  Activity (commits/month) | 2 | 9 | 2 | 4 | 2 | 13 | +|  Total issues | 3271 | 905 | 193 | 194 | 24 | 5 | |  Issues closed/open | 68 | 3 | 8 | 5 | 0 open | 0 open | |  Stars | 49.4k | 15k | 2k | 1.3k | 31 | 194 | -| Проходит ли CI | + | + | + | - | + | ? | +| Passes CI | + | + | + | - | + | ? | -> ¹ Опционально. +> ¹ Optional. -## Сравнение универсальных инструментов +## Comparison of universal tools -| Критерий | Boost.Program_options +| Criterion | Boost.Program_options |:---|:---:| -| Зависимости | +¹ | -| **Источники** | | | +| Dependencies | +¹ | +| **Sources** | | | |  CLI (argv) | + | + | |  env | + | + | -|  Файлы | INI | -| Стандарт C++ | ≥ C++3 | -| **Поддерживает стандарт иерархии** | | | -|  Linux | + | -|  Windows | + | +|  Files | INI | +| C++ standard | ≥ C++3 | +| **Supports standard hierarchy** | | | +|  Linux | + | +|  Windows | + | |  MacOS | + | -| Способ распространения | статическая/динамическая² | -| **ОС** | | | -|  Linux | + (GCC 5+, Clang 3.6+) | +| Distribution | static/dynamic² | +| **OS** | | | +|  Linux | + (GCC 5+, Clang 3.6+) | |  Windows | + (MSVC 2015 (vc140)+) | |  macOS | + (AppleClang) | -| **Сообщество** | | | -|  Активность (коммитов/мес) | 12 | -|  Issues всего | 400 | -|  Issues closed/open | 1 | +| **Community** | | | +|  Activity (commits/month) | 12 | +|  Total issues | 400 | +|  Issues closed/open | 1 | |  Stars | 9.4k | -| Проходит ли CI | + | + | +| Passes CI | + | + | -> ¹ Список зависимостей: +> ¹ Dependency list: > 1. Boost.Any > 2. Boost.Bind > 3. Boost.Config @@ -112,10 +112,10 @@ > 9. Boost.Smart Ptr > 10. Boost.ThrowException > 11. Boost.Tokenizer -> 12. Boost.Type Traits +> 12. Boost.Type Traits -> ² Опционально. +> ² Optional. -### Итог: -По результатам сравнения, вероятно, лучшим вариантом будет использование `CLI11` и `nlohmann/json`, так как они, в отличие от `Boost.program_options`, не требуют зависимостей и являются header-only. +### Conclusion: +Based on the comparison results, the best choice is likely to use `CLI11` and `nlohmann/json`, since, unlike `Boost.program_options`, they require no dependencies and are header-only. \ No newline at end of file diff --git a/docs/UserGuide.md b/docs/UserGuide.md index 27a1fc101..d7282337d 100644 --- a/docs/UserGuide.md +++ b/docs/UserGuide.md @@ -1,33 +1,33 @@ # User Guide -Руководство пользователя библиотеки spla. Содержит сценарии использования механизма конфигурирования: от быстрого запуска без настройки до запуска тестов в CI. Полный справочник всех параметров, флагов и переменных окружения приведён в [User Manual](UserManual.md). +The user guide for the spla library. Contains usage scenarios for the configuration mechanism: from a quick start without configuration to running tests in CI. The complete reference of all parameters, flags and environment variables is given in the [User Manual](UserManual.md). -## Содержание +## Contents -1. [Проверка окружения](#проверка-окружения) -2. [Сценарий 1. Быстрый запуск без настройки](#сценарий-1-быстрый-запуск-без-настройки) -3. [Сценарий 2. Выбор между CPU и GPU без указания индексов](#сценарий-2-выбор-между-cpu-и-gpu-без-указания-индексов) -4. [Сценарий 3. Несколько устройств и режимов в одном файле](#сценарий-3-несколько-устройств-и-режимов-в-одном-файле) -5. [Сценарий 4. Запуск в CI с файлом из репозитория](#сценарий-4-запуск-в-ci-с-файлом-из-репозитория) -6. [Приоритет источников конфигурации](#приоритет-источников-конфигурации) -7. [Где лежат файлы конфигурации](#где-лежат-файлы-конфигурации) +1. [Environment check](#environment-check) +2. [Scenario 1. Quick start without configuration](#scenario-1-quick-start-without-configuration) +3. [Scenario 2. Choosing between CPU and GPU without specifying indexes](#scenario-2-choosing-between-cpu-and-gpu-without-specifying-indexes) +4. [Scenario 3. Multiple devices and modes in one file](#scenario-3-multiple-devices-and-modes-in-one-file) +5. [Scenario 4. Running in CI with a file from the repository](#scenario-4-running-in-ci-with-a-file-from-the-repository) +6. [Priority of configuration sources](#priority-of-configuration-sources) +7. [Where the configuration files are located](#where-the-configuration-files-are-located) -## Проверка окружения +## Environment check -После установки выполните команду, которая подтверждает, что библиотека готова к использованию: +After installation, run the command that confirms the library is ready to use: ```bash spla --softcheck ``` -Команда: +The command: -1. Читает конфигурационный файл, поставляемый библиотекой. -2. Инициализирует OpenCL, выбирает платформу и устройство. -3. Запускает простое тестовое задание `2 + 3`. -4. Сообщает статус. +1. Reads the configuration file shipped with the library. +2. Initializes OpenCL, selects the platform and device. +3. Runs a simple test task `2 + 3`. +4. Reports the status. -Пример успешного вывода: +Example of successful output: ```bash $ spla --softcheck @@ -39,23 +39,23 @@ $ spla --softcheck [spla:check] SUCCESS - spla works correctly ``` -## Сценарий 1. Быстрый запуск без настройки +## Scenario 1. Quick start without configuration -Вы хотите получить работоспособное приложение без настройки - ничего настраивать не нужно. Библиотека использует параметры по умолчанию из конфигурационного файла, поставляемого вместе с библиотекой. +You want a working application without configuration - nothing needs to be configured. The library uses the default parameters from the configuration file shipped with the library. ```bash ./program ``` -Сценарий работает одинаково на Linux, macOS и Windows. Если GPU недоступен, библиотека по умолчанию автоматически переключится на CPU (параметр `if_gpu_unavailable: "use_cpu"`), сообщив об этом. +The scenario works the same on Linux, macOS and Windows. If GPU is unavailable, the library will automatically switch to CPU by default (the `if_gpu_unavailable: "use_cpu"` parameter), reporting it. -Перед первым запуском рекомендуется выполнить [`spla --softcheck`](#проверка-окружения), чтобы убедиться, что всё необходимое для работы spla установлено. +Before the first run it is recommended to run [`spla --softcheck`](#environment-check) to make sure that everything required for spla is installed. -## Сценарий 2. Выбор между CPU и GPU без указания индексов +## Scenario 2. Choosing between CPU and GPU without specifying indexes -Вы хотите управлять типом устройства, но не указывать конкретные индексы OpenCL-платформ и устройств. +You want to control the device type, but not specify concrete OpenCL platform and device indexes. -Тип устройства задаётся параметром `backend` в конфигурационном файле: +The device type is set by the `backend` parameter in the configuration file: ```json { @@ -65,15 +65,15 @@ $ spla --softcheck } ``` -- `"gpu"` - использовать первое доступное GPU, -- `"cpu"` - использовать CPU, -- `"any"` - использовать первое доступное устройство любого типа. +- `"gpu"` - use the first available GPU, +- `"cpu"` - use the CPU, +- `"any"` - use the first available device of any type. -Индексы `platform_index` и `device_index` при этих значениях игнорируются. +The `platform_index` and `device_index` indexes are ignored with these values. -### Поведение при отсутствии GPU +### Behavior when GPU is unavailable -Если выбран `backend: "gpu"`, но GPU недоступен, поведение определяется параметром `if_gpu_unavailable`: +If `backend: "gpu"` is selected, but GPU is unavailable, the behavior is defined by the `if_gpu_unavailable` parameter: ```json { @@ -88,22 +88,22 @@ $ spla --softcheck } ``` -- `"use_cpu"` - библиотека переключается на CPU и продолжает работу, +- `"use_cpu"` - the library switches to CPU and continues working, - `"abort"` - - библиотека возвращает ошибку и не продолжает работу. + the library returns an error and does not continue. -Запуск нужной конфигурации: +Running the required configuration: ```bash ./program --spla-config=gpu_or_cpu ./program --spla-config=gpu_only ``` -`if_gpu_unavailable` применяется при `backend: "gpu"`, `"any"` и `"by_index"`. При `backend: "cpu"` параметр игнорируется. +`if_gpu_unavailable` is applied with `backend: "gpu"`, `"any"` and `"by_index"`. With `backend: "cpu"` the parameter is ignored. -## Сценарий 3. Несколько устройств и режимов в одном файле +## Scenario 3. Multiple devices and modes in one file -Вы регулярно запускаете одну и ту же программу на разных GPU и в разных режимах - например, на GPU 0 и 1, в режиме отладки и в режиме измерения производительности. Вместо нескольких файлов конфигурации вы описываете всё в одном. +You regularly run the same program on different GPUs and in different modes - for example, on GPU 0 and 1, in debug mode and in performance measurement mode. Instead of several configuration files, you describe everything in one. ```json { @@ -137,7 +137,7 @@ $ spla --softcheck } ``` -Запуск: +Running: ```bash ./program --spla-config=gpu1 @@ -146,13 +146,13 @@ $ spla --softcheck ./program --spla-config=bench_gpu0 ``` -Конфигурации, наследуемые через `extends`, применяются по порядку: каждый следующий родитель переопределяет предыдущего, а параметры самой конфигурации переопределяют всех родителей. Циклическое наследование обнаруживается и приводит к ошибке. +Configurations inherited through `extends` are applied in order: each next parent overrides the previous one, and the parameters of the configuration itself override all parents. Circular inheritance is detected and results in an error. -## Сценарий 4. Запуск в CI с файлом из репозитория +## Scenario 4. Running in CI with a file from the repository -Вам нужно запустить тесты в CI с отдельным файлом конфигурации. +You need to run tests in CI with a separate configuration file. -В среде CI неудобно и нежелательно трогать системный и пользовательский файлы конфигурации, а конфигурации тестов должны лежать в репозитории. Поэтому конфигурации описывают в отдельном файле внутри репозитория и указывают путь к нему при запуске вместе с именем конфигурации - это аргументы командной строки `--spla-config-file` и `--spla-config`. +In a CI environment it is inconvenient and undesirable to touch the system and user configuration files, and the test configurations must live in the repository. Therefore the configurations are described in a separate file inside the repository and its path is given at launch together with the configuration name - these are the command line arguments `--spla-config-file` and `--spla-config`. ``` my_project/ @@ -234,28 +234,28 @@ jobs: run: python src/my_app.py --spla-config-file=.github/workflows/ci_spla_conf.json --spla-config=${{ matrix.config }} ``` -Путь к файлу и имя конфигурации передаются при запуске как аргументы команды, а не через переменные окружения - в CI это делает команду запуска самодостаточной и воспроизводимой. +The file path and the configuration name are passed at launch as command arguments, not through environment variables - in CI this makes the launch command self-contained and reproducible. -## Приоритет источников конфигурации +## Priority of configuration sources -Источники применяются в порядке убывания приоритета: параметры из более приоритетного источника переопределяют менее приоритетные. Это важно для сценариев: любой флаг или переменная окружения перебивает значения из файлов. +Sources are applied in descending priority order: parameters from a higher-priority source override lower-priority ones. This matters for the scenarios: any flag or environment variable overrides values from files. -| # | Источник | +| # | Source | |---:|:---| -| 1 | Аргументы командной строки (`--spla-*`) | -| 2 | Переменные окружения (`SPLA_*`) | -| 3 | Файл с явно указанным путём (`--spla-config-file`) | -| 4 | Пользовательский конфигурационный файл | -| 5 | Системный конфигурационный файл | -| 6 | Конфигурационный файл, поставляемый библиотекой | +| 1 | Command line arguments (`--spla-*`) | +| 2 | Environment variables (`SPLA_*`) | +| 3 | File with an explicitly specified path (`--spla-config-file`) | +| 4 | User configuration file | +| 5 | System configuration file | +| 6 | Configuration file shipped with the library | -Если имя конфигурации не указано, используется конфигурация `"default"` из файла, поставляемого библиотекой. Подробно о порядке сбора и слиянии источников - в [User Manual](UserManual.md#обзор-механизма-конфигурирования). +If the configuration name is not specified, the `"default"` configuration from the file shipped with the library is used. For details on the collection order and merging of sources, see the [User Manual](UserManual.md#configuration-mechanism-overview). -## Где лежат файлы конфигурации +## Where the configuration files are located -- **Поставляемый библиотекой** - рядом с файлом библиотеки (в пакете pyspla - внутри установленного пакета). -- **Системный** - Linux: `/etc/spla/spla_conf.json`. -- **Пользовательский** - Linux: `~/.config/spla/spla_conf.json`. -- **Явный** - любой путь через `--spla-config-file`. +- **Shipped with the library** - next to the library file (in the pyspla package - inside the installed package). +- **System** - Linux: `/etc/spla/spla_conf.json`. +- **User** - Linux: `~/.config/spla/spla_conf.json`. +- **Explicit** - any path via `--spla-config-file`. -Пути для macOS и Windows и правила «файла нет / файл не открывается» - в [User Manual](UserManual.md#конфигурационные-файлы). \ No newline at end of file +Paths for macOS and Windows and the rules for "file missing / file cannot be opened" are in the [User Manual](UserManual.md#configuration-files). \ No newline at end of file diff --git a/docs/UserManual.md b/docs/UserManual.md index f7dd6d371..48dc94db1 100644 --- a/docs/UserManual.md +++ b/docs/UserManual.md @@ -1,77 +1,77 @@ # User Manual -Мануал по механизму конфигурирования библиотеки spla. Это справочник: полное описание параметров, источников конфигурации, правил валидации и статусов. Практические сценарии использования приведены в [User Guide](UserGuide.md). +A manual for the spla library configuration mechanism. This is a reference: a complete description of the parameters, configuration sources, validation rules and statuses. Practical usage scenarios are given in the [User Guide](UserGuide.md). -## Содержание +## Contents -1. [НАЗВАНИЕ](#название) -2. [ОБЗОР МЕХАНИЗМА КОНФИГУРИРОВАНИЯ](#обзор-механизма-конфигурирования) -3. [ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ](#параметры-командной-строки) -4. [ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ](#переменные-окружения) -5. [КОНФИГУРАЦИОННЫЕ ФАЙЛЫ](#конфигурационные-файлы) -6. [КОНФИГУРАЦИИ И НАСЛЕДОВАНИЕ](#конфигурации-и-наследование) -7. [ВАЛИДАЦИЯ ПАРАМЕТРОВ](#валидация-параметров) -8. [СТАТУСЫ И ПОВЕДЕНИЕ ПРИ ОШИБКАХ](#статусы-и-поведение-при-ошибках) +1. [NAME](#name) +2. [CONFIGURATION MECHANISM OVERVIEW](#configuration-mechanism-overview) +3. [COMMAND LINE PARAMETERS](#command-line-parameters) +4. [ENVIRONMENT VARIABLES](#environment-variables) +5. [CONFIGURATION FILES](#configuration-files) +6. [CONFIGURATIONS AND INHERITANCE](#configurations-and-inheritance) +7. [PARAMETER VALIDATION](#parameter-validation) +8. [STATUSES AND ERROR BEHAVIOR](#statuses-and-error-behavior) -## НАЗВАНИЕ +## NAME -spla - фреймворк для математических вычислений с ускорением на GPU. Библиотека предоставляет примитивы разреженной линейной алгебры (матрицы, векторы, скаляры) и широкий спектр операций. +spla - a framework for GPU-accelerated mathematical computations. The library provides sparse linear algebra primitives (matrices, vectors, scalars) and a wide range of operations. -Для большинства пользователей важно, на каком устройстве будет запускаться их проект, поэтому библиотека предоставляет механизм конфигурирования: явное указание GPU, OpenCL-платформы, количества очередей команд и других параметров, влияющих на производительность и удобство пользователя. +For most users it matters on which device their project runs, so the library provides a configuration mechanism: explicit GPU selection, OpenCL platform, number of command queues and other parameters that affect performance and user convenience. -## ОБЗОР МЕХАНИЗМА КОНФИГУРИРОВАНИЯ +## CONFIGURATION MECHANISM OVERVIEW -Конфигурация spla собирается из шести источников, применяемых в порядке убывания приоритета. +The spla configuration is assembled from six sources, applied in descending order of priority. -| # | Источник | Как задаётся | +| # | Source | How it is set | |---:|:---|:---| -| 1 | Аргументы командной строки | флаги `--spla-*` | -| 2 | Переменные окружения | переменные `SPLA_*` | -| 3 | Файл с явно указанным путём | флаг `--spla-config-file` или `SPLA_CONFIG_FILE` | -| 4 | Пользовательский файл | `~/.config/spla/spla_conf.json` (Linux) и аналоги | -| 5 | Системный файл | `/etc/spla/spla_conf.json` (Linux) и аналоги | -| 6 | Файл библиотеки | `spla_conf.json` рядом с файлом библиотеки | +| 1 | Command line arguments | `--spla-*` flags | +| 2 | Environment variables | `SPLA_*` variables | +| 3 | File with an explicitly specified path | the `--spla-config-file` flag or `SPLA_CONFIG_FILE` | +| 4 | User file | `~/.config/spla/spla_conf.json` (Linux) and equivalents | +| 5 | System file | `/etc/spla/spla_conf.json` (Linux) and equivalents | +| 6 | Library file | `spla_conf.json` next to the library file | -Порядок сбора: +Collection order: -1. Читаются конфигурационные файлы (6 → 5 → 4 → 3) и **сливаются по именам конфигураций**: одноимённые конфигурации из разных файлов объединяются по параметрам, уникальные добавляются. -2. Выбирается активная конфигурация: имя из `--spla-config` / `SPLA_CONFIG`, по умолчанию - `"default"`. -3. Применяется выбранная конфигурация вместе с родителями из `extends`. -4. Поверх применяются переменные окружения, затем аргументы командной строки (наивысший приоритет). +1. Configuration files are read (6 → 5 → 4 → 3) and **merged by configuration name**: configurations with the same name from different files are merged parameter by parameter, unique ones are added. +2. The active configuration is selected: the name from `--spla-config` / `SPLA_CONFIG`, `"default"` by default. +3. The selected configuration is applied together with the parents from `extends`. +4. Environment variables are applied on top, then command line arguments (highest priority). -Результат попадает в итоговую конфигурацию, которая используется при инициализации ускорителя (выбор платформы и устройства, создание очередей команд, аллокатора, уровня логирования). +The result goes into the final configuration, which is used when initializing the accelerator (platform and device selection, creation of command queues, allocator, verbosity level). -## ПАРАМЕТРЫ КОМАНДНОЙ СТРОКИ +## COMMAND LINE PARAMETERS -Все флаги spla начинаются с `--spla-`. Флаги, не начинающиеся с `--spla-`, принадлежат программе, использующей библиотеку, и игнорируются механизмом конфигурирования. +All spla flags start with `--spla-`. Flags that do not start with `--spla-` belong to the program using the library and are ignored by the configuration mechanism. -| Флаг | Тип | Описание | +| Flag | Type | Description | |:---|:---|:---| -| `--spla-help` | - | Вывести справку и завершиться | -| `--spla-version` | - | Вывести версию библиотеки и завершиться | -| `--spla-config` | string | Имя конфигурации для применения. По умолчанию используется конфигурация `"default"` | -| `--spla-config-file` | path | Путь к конфигурационному файлу. | -| `--spla-backend` | string | Тип устройства: `gpu`, `cpu`, `any`, `by_index` | -| `--spla-platform-index` | int | Индекс OpenCL-платформы. Только при `backend=by_index` | -| `--spla-device-index` | int | Индекс OpenCL-устройства внутри платформы. Только при `backend=by_index` | -| `--spla-if-gpu-unavailable` | string | Поведение при недоступности GPU: `use_cpu` - переключиться на CPU, `abort` - вернуть ошибку | -| `--spla-queues-count` | int | Количество командных очередей OpenCL | -| `--spla-profiling` | bool | Профилирование командных очередей: `true`, `false` | -| `--spla-allocator-type` | string | Тип аллокатора: `general`, `linear` | -| `--spla-linear-alloc-size` | int | Размер линейного аллокатора в байтах. Требуется при `allocator_type=linear`, игнорируется при `general` | -| `--spla-verbosity` | int | Уровень логирования: `0` - нет вывода, `1` - только ошибки, `2` - ошибки и предупреждения, `3` - все сообщения | - -### Пример +| `--spla-help` | - | Show help and exit | +| `--spla-version` | - | Show the library version and exit | +| `--spla-config` | string | Name of the configuration to apply. By default the `"default"` configuration is used | +| `--spla-config-file` | path | Path to a configuration file. | +| `--spla-backend` | string | Device type: `gpu`, `cpu`, `any`, `by_index` | +| `--spla-platform-index` | int | OpenCL platform index. Only when `backend=by_index` | +| `--spla-device-index` | int | Index of the OpenCL device within the platform. Only when `backend=by_index` | +| `--spla-if-gpu-unavailable` | string | Behavior when GPU is unavailable: `use_cpu` - switch to CPU, `abort` - return an error | +| `--spla-queues-count` | int | Number of OpenCL command queues | +| `--spla-profiling` | bool | Profiling of command queues: `true`, `false` | +| `--spla-allocator-type` | string | Allocator type: `general`, `linear` | +| `--spla-linear-alloc-size` | int | Linear allocator size in bytes. Required when `allocator_type=linear`, ignored when `general` | +| `--spla-verbosity` | int | Verbosity level: `0` - no output, `1` - errors only, `2` - errors and warnings, `3` - all messages | + +### Example ```bash ./my_program --spla-config-file=/etc/spla/spla_conf.json --spla-config=bench --spla-verbosity=0 ``` -## ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ +## ENVIRONMENT VARIABLES -Для каждого параметра командной строки (кроме `--spla-help` и `--spla-version`) существует аналог в виде переменной окружения. +For each command line parameter (except `--spla-help` and `--spla-version`) there is an environment variable equivalent. -| Переменная | Аналог флага | +| Variable | Flag equivalent | |:---|:---| | `SPLA_CONFIG` | `--spla-config` | | `SPLA_CONFIG_FILE` | `--spla-config-file` | @@ -85,36 +85,36 @@ spla - фреймворк для математических вычислени | `SPLA_LINEAR_ALLOC_SIZE` | `--spla-linear-alloc-size` | | `SPLA_VERBOSITY` | `--spla-verbosity` | -### Пример +### Example ```bash SPLA_CONFIG=bench SPLA_VERBOSITY=1 ./my_program ``` -## КОНФИГУРАЦИОННЫЕ ФАЙЛЫ +## CONFIGURATION FILES -Формат файла - JSON. Файл состоит из набора именованных конфигураций,каждая конфигурация - это набор параметров библиотеки. +The file format is JSON. A file consists of a set of named configurations; each configuration is a set of library parameters. -### Ключи конфигурации +### Configuration keys -| Ключ | Тип | Описание | Требования | +| Key | Type | Description | Requirements | |:---|:---|:---|:---| -| `extends` | array of string | Список конфигураций-родителей | Имена конфигураций со всех уровней файлов | -| `backend` | string | Тип устройства: `gpu`, `cpu`, `any`, `by_index` | Обязателен | -| `platform_index` | int | Индекс OpenCL-платформы | Обязателен при `backend=by_index`, иначе игнорируется | -| `device_index` | int | Индекс OpenCL-устройства | Обязателен при `backend=by_index`, иначе игнорируется | -| `if_gpu_unavailable` | string | Поведение при недоступности GPU: `use_cpu`, `abort` | Обязателен при `backend != cpu`, при `backend=cpu` игнорируется | -| `queues_count` | int | Количество командных очередей | Обязателен, ≥ 1 | -| `profiling` | bool | Профилирование очередей | Обязателен | -| `allocator_type` | string | Тип аллокатора: `general`, `linear` | Обязателен | -| `linear_alloc_size` | int | Размер линейного аллокатора (байт) | Обязателен при `allocator_type=linear`, при `general` игнорируется | -| `verbosity` | int | Уровень логирования 0..3 | Обязателен | +| `extends` | array of string | List of parent configurations | Names of configurations from all file levels | +| `backend` | string | Device type: `gpu`, `cpu`, `any`, `by_index` | Required | +| `platform_index` | int | OpenCL platform index | Required when `backend=by_index`, otherwise ignored | +| `device_index` | int | OpenCL device index | Required when `backend=by_index`, otherwise ignored | +| `if_gpu_unavailable` | string | Behavior when GPU is unavailable: `use_cpu`, `abort` | Required when `backend != cpu`, ignored when `backend=cpu` | +| `queues_count` | int | Number of command queues | Required, ≥ 1 | +| `profiling` | bool | Queue profiling | Required | +| `allocator_type` | string | Allocator type: `general`, `linear` | Required | +| `linear_alloc_size` | int | Linear allocator size (bytes) | Required when `allocator_type=linear`, ignored when `general` | +| `verbosity` | int | Verbosity level 0..3 | Required | -### Файл, поставляемый библиотекой +### File shipped with the library -Имя конфигурации `"default"` может быть определено **только** в файле, поставляемом библиотекой. Определение конфигурации с именем `"default"` в любом другом файле - ошибка парсинга. +The configuration name `"default"` can be defined **only** in the file shipped with the library. Defining a configuration named `"default"` in any other file is a parsing error. -Поставляемый файл имеет следующую структуру: +The shipped file has the following structure: ```json { @@ -131,59 +131,59 @@ SPLA_CONFIG=bench SPLA_VERBOSITY=1 ./my_program } ``` -### Расположение файлов +### File locations -**Файл библиотеки** - рядом с файлом библиотеки: Windows - рядом с DLL, Linux/macOS - рядом с `.so`/`.dylib` (путь определяется через адрес загруженной библиотеки). В составе пакета pyspla - внутри директории установленного Python-пакета. +**Library file** - next to the library file: Windows - next to the DLL, Linux/macOS - next to the `.so`/`.dylib` (the path is determined via the address of the loaded library). Within the pyspla package - inside the installed Python package directory. -**Системный файл:** +**System file:** > Linux: `/etc/spla/spla_conf.json` \ > macOS: `/Library/Application Support/spla/spla_conf.json` \ > Windows: `%ProgramData%\spla\spla_conf.json` -**Пользовательский файл:** +**User file:** > Linux: `~/.config/spla/spla_conf.json` \ > macOS: `~/Library/Application Support/spla/spla_conf.json` \ > Windows: `%APPDATA%\spla\spla_conf.json` -**Файл, заданный явно** - любой путь, заданный через `--spla-config-file` / `SPLA_CONFIG_FILE`. +**Explicitly set file** - any path given via `--spla-config-file` / `SPLA_CONFIG_FILE`. -### Семантика отсутствующих и неоткрывающихся файлов +### Semantics of missing and unopenable files -| Файл | Отсутствует | Существует, но не открывается | +| File | Missing | Exists but cannot be opened | |:---|:---|:---| -| Файл библиотеки | ошибка `FileNotExists` (обязателен) | ошибка `OpenFileError` | -| Системный | пропуск | ошибка `OpenFileError` | -| Пользовательский | пропуск | ошибка `OpenFileError` | -| Явный (если указан) | ошибка `FileNotExists` | ошибка `OpenFileError` | +| Library file | error `FileNotExists` (required) | error `OpenFileError` | +| System | skipped | error `OpenFileError` | +| User | skipped | error `OpenFileError` | +| Explicit (if specified) | error `FileNotExists` | error `OpenFileError` | -## КОНФИГУРАЦИИ И НАСЛЕДОВАНИЕ +## CONFIGURATIONS AND INHERITANCE -### Выбор активной конфигурации +### Choosing the active configuration ```bash -./program --spla-config=gpu1 # флаг -SPLA_CONFIG=gpu1 ./program # или переменная окружения +./program --spla-config=gpu1 # flag +SPLA_CONFIG=gpu1 ./program # or environment variable ``` -Если имя не указано, используется конфигурация `"default"` из файла, поставляемого библиотекой. +If the name is not specified, the `"default"` configuration from the file shipped with the library is used. -### Слияние файлов +### Merging files -Конфигурации из файлов библиотеки, системного, пользовательского и явного сливаются по именам: одноимённые конфигурации объединяются по параметрам, уникальные добавляются. Параметры конфигурации из файла с более высоким приоритетом переопределяют параметры одноимённой конфигурации из файла с более низким приоритетом. +Configurations from the library, system, user and explicit files are merged by name: configurations with the same name are merged parameter by parameter, unique ones are added. Parameters of a configuration from a file with higher priority override the parameters of the same-named configuration from a file with lower priority. -### Наследование `extends` +### Inheritance via `extends` -Если конфигурация содержит поле `extends`, библиотека сначала применяет указанные в нём конфигурации по порядку: последняя в списке переопределяет предыдущие. Параметры самой конфигурации применяются последними и переопределяют всех родителей. +If a configuration contains an `extends` field, the library first applies the configurations listed in it in order: the last one in the list overrides the previous ones. The parameters of the configuration itself are applied last and override all parents. -Если конфигурация не содержит `extends`, применяются только её собственные параметры. +If a configuration does not contain `extends`, only its own parameters are applied. -Имена в `extends` берутся из всех конфигураций, определённых во всех файлах. Это позволяет наследовать конфигурации, определённые на другом уровне, например пользовательская конфигурация может наследовать `"default"` из файла библиотеки. +Names in `extends` are taken from all configurations defined in all files. This allows inheriting configurations defined at another level, for example, a user configuration can inherit `"default"` from the library file. -Циклическое наследование обнаруживается и приводит к статусу `ConfigurationCycle`. +Circular inheritance is detected and results in the `ConfigurationCycle` status. -Пример цикла - конфигурации наследуют друг друга напрямую: +Example of a cycle - configurations inherit each other directly: ```json { @@ -192,11 +192,11 @@ SPLA_CONFIG=gpu1 ./program # или переменная окружени } ``` -Такая конфигурация отклоняется при загрузке (`ConfigurationCycle`). Циклом является и самоссылка (`"extends": ["a"]` внутри конфигурации `a`). Ромбовидное наследование (`a` → `b`, `a` → `c`, где `b` и `c` оба наследуют `d`) циклом не является. +Such a configuration is rejected when loading (`ConfigurationCycle`). A self-reference is also a cycle (`"extends": ["a"]` inside configuration `a`). Diamond inheritance (`a` → `b`, `a` → `c`, where `b` and `c` both inherit `d`) is not a cycle. -### Пример +### Example -Файл, поставляемый библиотекой: +File shipped with the library: ```json { @@ -211,7 +211,7 @@ SPLA_CONFIG=gpu1 ./program # или переменная окружени } ``` -Пользовательский файл: +User file: ```json { @@ -227,79 +227,79 @@ SPLA_CONFIG=gpu1 ./program # или переменная окружени } ``` -Итоговый набор параметров конфигурации `gpu0`: +Final set of parameters of the `gpu0` configuration: -| Параметр | Значение | Источник | +| Parameter | Value | Source | |:---|:---|:---| -| backend | `by_index` | конфигурация `gpu0` | -| platform_index | `0` | конфигурация `gpu0` | -| device_index | `0` | конфигурация `gpu0` | -| if_gpu_unavailable | `abort` | конфигурация `gpu0` | -| queues_count | `1` | файл библиотеки (`default`) | -| profiling | `true` | конфигурация `gpu0` | -| allocator_type | `general` | файл библиотеки (`default`) | -| verbosity | `2` | файл библиотеки (`default`) | +| backend | `by_index` | configuration `gpu0` | +| platform_index | `0` | configuration `gpu0` | +| device_index | `0` | configuration `gpu0` | +| if_gpu_unavailable | `abort` | configuration `gpu0` | +| queues_count | `1` | library file (`default`) | +| profiling | `true` | configuration `gpu0` | +| allocator_type | `general` | library file (`default`) | +| verbosity | `2` | library file (`default`) | -## ВАЛИДАЦИЯ ПАРАМЕТРОВ +## PARAMETER VALIDATION -После сборки конфигурация из всех источников проходит валидацию. +After assembly, the configuration from all sources is validated. -### Ошибки (конфигурация недействительна) +### Errors (the configuration is invalid) -| Параметр | Требование | +| Parameter | Requirement | |:---|:---| -| `backend` | Обязателен, одно из: `gpu`, `cpu`, `any`, `by_index` | -| `platform_index`, `device_index` | Обязательны при `backend=by_index`, должны быть ≥ 0 | -| `if_gpu_unavailable` | Обязателен при `backend != cpu`, одно из: `use_cpu`, `abort` | -| `queues_count` | Обязателен, ≥ 1 | -| `profiling` | Обязателен | -| `allocator_type` | Обязателен, одно из: `general`, `linear` | -| `linear_alloc_size` | Обязателен при `allocator_type=linear` | -| `verbosity` | Обязателен, 0..3 | - -### Предупреждения (параметр игнорируется, но конфигурация действительна) - -| Ситуация | Сообщение | +| `backend` | Required, one of: `gpu`, `cpu`, `any`, `by_index` | +| `platform_index`, `device_index` | Required when `backend=by_index`, must be ≥ 0 | +| `if_gpu_unavailable` | Required when `backend != cpu`, one of: `use_cpu`, `abort` | +| `queues_count` | Required, ≥ 1 | +| `profiling` | Required | +| `allocator_type` | Required, one of: `general`, `linear` | +| `linear_alloc_size` | Required when `allocator_type=linear` | +| `verbosity` | Required, 0..3 | + +### Warnings (the parameter is ignored, but the configuration is valid) + +| Situation | Message | |:---|:---| -| `platform_index`/`device_index` заданы при `backend != by_index` | параметр игнорируется | -| `if_gpu_unavailable` задан при `backend=cpu` | параметр игнорируется | -| `linear_alloc_size` задан при `allocator_type=general` | параметр игнорируется | +| `platform_index`/`device_index` set when `backend != by_index` | the parameter is ignored | +| `if_gpu_unavailable` set when `backend=cpu` | the parameter is ignored | +| `linear_alloc_size` set when `allocator_type=general` | the parameter is ignored | -### Поведение при недоступности устройства +### Behavior when the device is unavailable -Реализовано в инициализации ускорителя: +Implemented in accelerator initialization: -| Конфигурация | GPU доступен | GPU недоступен | +| Configuration | GPU available | GPU unavailable | |:---|:---|:---| -| `backend=gpu`, `if_gpu_unavailable=use_cpu` | используется GPU | ищется OpenCL-устройство CPU, нет - `DeviceNotFound` | -| `backend=gpu` / `any`, `if_gpu_unavailable=abort` | используется GPU | ошибка `DeviceNotFound`, при запуске через `pyspla` поднимается `SplaFailedInitialize` | -| `backend=cpu` | - | ищется OpenCL-устройство CPU, нет - `DeviceNotFound` | -| `backend=by_index` | - | выбирается платформа/устройство по индексам, устройство недоступно - `DeviceNotFound` | +| `backend=gpu`, `if_gpu_unavailable=use_cpu` | GPU is used | an OpenCL CPU device is searched for, if none - `DeviceNotFound` | +| `backend=gpu` / `any`, `if_gpu_unavailable=abort` | GPU is used | error `DeviceNotFound`; when run through `pyspla`, `SplaFailedInitialize` is raised | +| `backend=cpu` | - | an OpenCL CPU device is searched for, if none - `DeviceNotFound` | +| `backend=by_index` | - | the platform/device is selected by indexes; if the device is unavailable - `DeviceNotFound` | -## СТАТУСЫ И ПОВЕДЕНИЕ ПРИ ОШИБКАХ +## STATUSES AND ERROR BEHAVIOR -Механизм конфигурирования возвращает один из следующих статусов. +The configuration mechanism returns one of the following statuses. -| Статус | Значение | +| Status | Meaning | |:---|:---| -| `Ok` | Конфигурация собрана и валидна | -| `HelpRequested` | Запрошена справка (`--spla-help`) - текст уже выведен | -| `VersionRequested` | Запрошена версия (`--spla-version`) - уже выведена | -| `CliOrEnvParseError` | Ошибка разбора аргументов командной строки или переменных окружения | -| `FileNotExists` | Отсутствует обязательный файл (файл библиотеки или явно указанный) | -| `OpenFileError` | Файл существует, но не может быть открыт | -| `ParseConfError` | Ошибка разбора JSON, неверный тип значения или `"default"` в не-библиотечном файле | -| `ConfigurationNotFound` | Указанное имя конфигурации не найдено ни в одном файле | -| `ConfigurationCycle` | Обнаружен цикл в `extends` | -| `MissedParameters` | Отсутствуют обязательные параметры | -| `PlatformNotFound` / `DeviceNotFound` | Устройство по конфигурации недоступно | -| `InvalidConfigParams` | Недопустимое значение параметра | - -### Поведение в CLI - -Инструмент командной строки `spla`: - -- `spla --softcheck` - проверка работоспособности окружения (конфигурирование, инициализация OpenCL, задание 2 + 3), -- `spla --spla-help` - справка, код возврата 0, -- `spla --spla-version` - версия библиотеки (например, `SPLA version: 0.0.5`), код возврата 0, -- при ошибке конфигурирования - сообщение об ошибке и код возврата 1. \ No newline at end of file +| `Ok` | The configuration is assembled and valid | +| `HelpRequested` | Help requested (`--spla-help`) - the text has already been printed | +| `VersionRequested` | Version requested (`--spla-version`) - already printed | +| `CliOrEnvParseError` | Error parsing command line arguments or environment variables | +| `FileNotExists` | A required file is missing (the library file or an explicitly specified one) | +| `OpenFileError` | The file exists but cannot be opened | +| `ParseConfError` | JSON parsing error, invalid value type, or `"default"` in a non-library file | +| `ConfigurationNotFound` | The specified configuration name was not found in any file | +| `ConfigurationCycle` | A cycle in `extends` was detected | +| `MissedParameters` | Required parameters are missing | +| `PlatformNotFound` / `DeviceNotFound` | The device required by the configuration is unavailable | +| `InvalidConfigParams` | Invalid parameter value | + +### CLI behavior + +The `spla` command line tool: + +- `spla --softcheck` - environment sanity check (configuration, OpenCL initialization, task 2 + 3), +- `spla --spla-help` - help, exit code 0, +- `spla --spla-version` - library version (for example, `SPLA version: 0.0.5`), exit code 0, +- on a configuration error - an error message and exit code 1. \ No newline at end of file