Przejdź do treści

SYCL

logo SYCL

Wprowadzenie

SYCL1 to wysokopoziomowy model programowania dla platform akcelerowanych, traktujący wielordzeniowe procesory również jako akceleratory. Oparty o C++, oferuje zunifikowany interfejs do programowania różnych urządzeń dostępnych w obrębie jednego komputera (tzw. strategia XPU). Dzięki temu umożliwia kompilację oraz uruchamianie tego samego kodu źródłowego na akceleratorach różnych typów (CPU, GPU, FPGA i inne) od różnych producentów.

Dzięki wspólnemu interfejsowi do programowania różnych akceleratorów, SYCL znacznie ułatwia:

  • przenośność kodu między architekturami,
  • programowanie heterogeniczne (np. jednoczesne obliczenia na CPU i GPU),
  • możliwość równoczesnego wykorzystania wielu akceleratorów (np. kilku kart GPU).

Dostępność

Model SYCL z założenia jest powiązany tylko z językiem C++. Jest on realizowany w ramach standardowej składni tego języka, poprzez bibliotekę dostarczającą funkcjonalności SYCL. Wymaga posiadania specjalnego kompilatora, od którego zależy zakres wspieranych urządzeń i architektur akceleratorów. Biblioteka SYCL oraz kompilator są dostarczane przez różnych implementatorów, każda implementacja posiada swoje cechy i możliwości.

Dwie wiodące implementacje – Intel oneAPI DPC++ oraz AdaptiveCpp – wspierają obecnie praktycznie pełną gamę najważniejszych platform sprzętowych:

  • CPU firm AMD i Intel,
  • GPU firm NVIDIA, AMD oraz Intel.

Istnieją także inne implementacje wspierające bardziej wyspecjalizowane i niszowe platformy. Więcej informacji w sekcji Implementacje️.

Co ważne, niezależnie od użytej implementacji, kompilacja oraz uruchomienie oprogramowania korzystającego z platform NVIDIA wymaga, z powodów licencyjnych, posiadania zainstalowanego odpowiedniego pakietu (CUDA Toolkit lub NVIDIA HPC SDK). Podobnie w przypadku platform AMD wymagany jest dostęp do pakietu ROCm, a Intel – oneAPI/LevelZero.

Inne technologie

SYCL może być używany równolegle z niżejpoziomowymi modelami programistycznymi przewidzianymi dla danej platformy sprzętowej (np. CUDA, HIP, OpenMP). Modele te są nazywane w standardzie SYCL backendami. Oprócz tego, implementacje SYCL mogą dostarczać dodatkowe interfejsy do backendów, które wspierają. Pozwala to na interoperacyjność między SYCL, a danym modelem programistycznym. Szczegóły zakresu możliwej interoperacyjności mogą się jednak różnić pomiędzy implementacjami SYCL. Więcej w sekcji Backendy️.

Model SYCL może być używany także w oprogramowaniu korzystającym z technologii do rozpraszania obliczeń takich jak MPI. Ciekawe możliwości w tym zakresie udostępnia biblioteka Celerity (patrz pozostałe implementacje️) ściśle integrująca SYCL z MPI.

Szczegóły

Zasadniczą rolą SYCL jest ułatwienie programiście zrównoleglania obliczeń oraz udostępnienie możliwości sprzętu w obrębie jednego komputera, bez konieczności korzystania z niskopoziomowych rozwiązań:

  • w przypadku CPU zdejmuje z programisty konieczność zarządzania wątkami i umożliwia zastosowanie koligacji (affinity) tj. przypisania obliczeń do konkretnych rdzeni (np. do rdzeni w obrębie tego samego węzła NUMA),
  • dla GPU oraz FPGA udostępnia narzędzia do realizacji specyficznych funkcjonalności takich jak zarządzanie granulacją zadań, transferami pamięci, a także przetwarzaniem potokowym (pipelining) czy odwijaniem pętli (loop unrolling).

Powyższe funkcjonalności są realizowane za pomocą wysokopoziomowych funkcji bibliotecznych. Jest to jednym z ważnych założeń standardu – kod w SYCL nie modyfikuje w żaden sposób składni języka C++ (nie rozszerza jej, ani nie wprowadza żadnych nowych słów kluczowych). W szczególności, funkcje akcelerowane (kernele):

  • nie muszą być oznaczane specjalnymi znacznikami (w przeciwieństwie do CUDA),
  • mogą znajdować się w jednym pliku razem z głównym kodem (tzw. single source programming, w przeciwieństwie do OpenCL).

Oprócz wysokopoziomowych interfejsów, ukrywających przed programistą szczegóły realizacji danej funkcjonalności, istnieją także alternatywne mechanizmy o API zbliżonych do klasycznych rozwiązań znanych z modeli CUDA czy OpenCL (na przykład wspomniane niżej mechanizmy USM czy ND-range).

Model programistyczny

Delegowanie obliczeń do wykonania na akceleratorze odbywa się poprzez specjalny obiekt kolejki, który należy stworzyć i powiązać z wybranym (lub domyślnym) akceleratorem. Następnie do kolejki wstawia się polecenia dla akceleratora w formie funkcji konfigurujących zadanie i zawierających właściwą funkcję obliczeniową, która stanie się kernelem. Ta ostatnia jest przekazywana poprzez wywołanie specjalnej funkcji parallel_for, która jednocześnie umożliwia określenie stopnia zrównoleglenia obliczeń. Na etapie kompilacji, po stronie kompilatora SYCL leży rola identyfikacji kodu akcelerowanego i kompilacji go pod wskazane rodzaje akceleratorów.

Schemat delegowania obliczeń

schemat delegowania obliczeń [źródło]

Zarządzanie transferem danych między pamięcią RAM a akceleratorami odbywa się automatycznie. Dane potrzebne do obliczeń w kernelu należy umieścić w specjalnym obiekcie bufora, a następnie odwoływać się do nich przez tzw. akcesory. Akcesory zazwyczaj definiuje się bezpośrednio przed zleceniem kernela, w funkcji wstawianej do kolejki. W najnowszym standardzie SYCL 2020 dostępny jest także alternatywny mechanizm USM (Unified Shared Memory). Bazuje on na wskaźnikach oraz wspólnej przestrzeni adresowej dla hosta i akceleratora. Transfery danych w USM mogą odbywać się, podobnie jak w przypadku buforów, automatycznie lub także poprzez ręczne wywołanie odpowiedniej funkcji (memcpy).

Konfiguracja równoległości

Zlecając zadanie do kolejki, właściwy kod obliczeniowy (czyli kernel który ma zostać policzony na akceleratorze) podaje się w formie funkcji, jako argument dla specjalnej funkcji uruchamiającej kernel. Podstawową funkcją wykorzystywaną w tym celu jest parallel_for(range, kernel). Pierwszy argument służy do określenia zakresu wykonania kernela, tj. tego jak wiele instancji kernela ma zostać wykonanych. Możliwe są tutaj dwa sposoby:

  • range, wariant podstawowy, w którym zakres może być podany jako pojedyncza liczba, co odpowiada 1-wymiarowej siatce obliczeń; może on zostać również zdefiniowany jako 2- lub 3-wymiarowy;
  • nd_range, bardziej zaawansowany wariant, pozwalający zdefiniować hierarchię obliczeń podobnie do składni <<<...>>> w CUDA; oprócz wymiaru siatki obliczeń (zakres globalny) podaje się również wymiar pojedynczego bloku (zakres lokalny), wedle którego mają zostać zgrupowane pojedyncze instancje kernela.

Porównanie z CUDA

Mechanizm nd_range różni się nieco od sposobu konfigurowania obliczeń w CUDA. W składni CUDA <<<numBlocks, threadsPerBlock>>> nie podaje się zakresu globalnego, wynika on z przemnożenia liczby bloków przez liczbę wątków. Z kolei w SYCL nie podaje się ile będzie bloków – liczba ta jest automatycznie obliczana z zakresu globalnego i lokalnego.

Warto dodać, że istnieje także możliwość zlecania pojedynczego zadania bez zrównoleglenia obliczeń. Służy do tego inna specjalna funkcja single_task(kernel).

Hierarchia obliczeń

W SYCL poszczególne instancje pojedynczego kernela reprezentowane są przez tzw. elementy robocze (work-item), które są łączone w grupy robocze (work-group). Jednostki te są odpowiednikami znanych z CUDA wątków (threads) oraz bloków (blocks).

Podział siatki obliczeń na grupy robocze

podział siatki obliczeń na grupy robocze [źródło]

W ramach wysokopoziomowego interfejsu range, grupy robocze są ukryte przed programistą, a ich rozmiary kontrolowane są przez bibliotekę uruchomieniową SYCL. Użycie nd_range pozwala na bezpośrednią kontrolę nad sposobem podziału elementów roboczych na grupy robocze, co, w niektórych przypadkach, może przełożyć się na lepszą wydajność. Dodatkowo grupy robocze umożliwiają zastosowanie mechanizmów synchronizacji i komunikacji oraz wspólnych obliczeń przez elementy robocze danej grupy roboczej.

Identyfikatory wewnątrz siatki obliczeń

identyfikatory wewnątrz siatki obliczeń [źródło]

Każdy element roboczy ma dostęp do swojego identyfikatora w zakresie pozwalającym na specjalizację zachowania poszczególnych instancji kernela. W zależności od użytej metody zrównoleglenia informacje te przekazywane są poprzez obiekty item lub nd_item będące argumentami poszczególnych instancji kernela. Obiekt item zawiera w sobie obiekt id będący identyfikatorem danej instancji (odpowiednik threadIdx z CUDA) oraz zakres range danego kernela. Z kolei nd_item zawiera zarówno identyfikator elementu roboczego w obrębie grupy roboczej jak i identyfikator grupy roboczej (odpowiedniki threadIdx oraz blockIdx z CUDA).

Więcej informacji można znaleźć w specyfikacji SYCL kernel execution model.

Przykład kodu

Schemat programu SYCL

schemat programu SYCL [źródło]

Powyższy przykład pozwala dopowiedzieć kilka kwestii. Biblioteka sycl/sycl.hpp dostarcza funkcjonalności zdefiniowane w standardzie. Polecenia konfigurujące zadanie dla akceleratora są nazywane “command group”. Funkcja która je zawiera otrzymuje jako argument handler nazywany “command group handler”. Funkcje uruchamiające kernele (parallel_for, single_task) są metodami obiektu tego handlera.

Backendy

Implementacje SYCL wewnątrz korzystają z istniejących, niżej poziomowych lub natywnych dla danej platformy sprzętowej, API. Takie bazowe interfejsy nazywane są backendami. Początkowo SYCL miał umożliwiać korzystanie jedynie z backendu OpenCL, jednak w nowszych wersjach przewidziano możliwość korzystania z różnorodnych backendów (np. CUDA, HIP, OpenMP).

Jednym z elementów standardu SYCL jest Backend API opisujący sposób dostępu – z poziomu kodu SYCL – do elementów backendu wykorzystywanych przez odpowiednie konstrukty w SYCL (przykładowo kolejka SYCL i CUDA Stream). Oprócz tego, poszczególne implementacje dostarczają dodatkowe funkcjonalności będące rozszerzeniami do obecnego standardu SYCL zwiększające możliwości współpracy pomiędzy SYCL, a backendem.

Założenie o niezależności interfejsu programistycznego (API) od docelowej platformy sprzętowej sprawia, że niektóre funkcjonalności specyficzne dla danego backendu lub architektury nie są obecnie dostępne w standardzie lub są oznaczone jako opcjonalne. Przykładem są technologie bezpośredniego dostępu do pamięci GPU za pośrednictwem interfejsów PCI Express/NVLink takie jak GPUDirect. Ich ewentualne wykorzystanie jest zależne od poszczególnych implementacji. Z drugiej strony SYCL umożliwia integrację z niżejpoziomowymi rozwiązaniami (np. CUDA lub HIP), co pozwala na ręczne optymalizowanie procedur pod konkretne architektury.

Terminologia

Poniżej zostały opisane podstawowe pojęcia. Pełną listę można znaleźć w słowniczku ze specyfikacji. Warto mieć na uwadze, że SYCL jako standard powstały podczas prac nad OpenCL dzieli z nim część koncepcji oraz nazewnictwa. Co więcej, wiele terminów dotyczących programowania akceleratorów wywodzi się z technik programowania GPU i dlatego posiada swoje odpowiedniki w technologii CUDA (oraz HIP) – patrz spis najistotniejszych analogii oraz sekcja Terminologia w CUDA.

  • host ─ Główny proces programu, wykonywany na CPU, delegujący obliczenia do wykonania na akceleratorach.
  • akcelerator (device) ─ Obiekt reprezentujący układ obliczeniowy (CPU, GPU, FPGA lub inny) na którym mogą być wykonywane obliczenia akcelerowane. W przypadku CPU może on zostać podzielony na mniejsze akceleratory, skupiające rdzenie z tej samej NUMY czy współdzielące pamięć cache konkretnego typu.
  • kernel ─ Podstawowa jednostka kodu przeznaczona do wykonania na akceleratorze. Może mieć postać funkcji, lambdy lub obiektu wywoływalnego (z przeładowanym operatorem nawiasów ()). Kod kernela musi spełniać określone wymagania, np. nie może alokować pamięci lub rzucać wyjątków.
  • selektor (selector) ─ Obiekt służący do wybrania konkretnego akceleratora spośród wszystkich dostępnych.
  • kolejka (queue) ─ Reprezentuje kolejkę zadań (kerneli) do wykonania na danym akceleratorze. Tworząc obiekt kolejki dokonuje się powiązania jej z konkretnym urządzeniem ─ w sposób domyślny, poprzez selektor lub obiekt urządzenia.
  • bufor (buffer) ─ Podstawowy mechanizm do zarządzania pamięcią oraz dostępem do tych samych danych zarówno przez hosta jak i akcelerator. Bufor można traktować jako fragment pamięci o ustalonym rozmiarze, może przechowywać dane 1-, 2- lub 3-wymiarowe. Na podstawie kolejności i sposobów dostępu do danych z bufora przez kernele, SYCL automatycznie decyduje o fizycznych transferach zawartości bufora pomiędzy hostem a konkretnym akceleratorem.
  • akcesor (accessor) ─ Obiekt umożliwiający dostęp do danych z bufora. Podczas tworzenia akcesora użytkownik musi wskazać konkretny bufor oraz określić tryb dostępu (read_only, write_only, read_write) a także może podać inne opcjonalne parametry, na podstawie których dostęp do danych zostaje zoptymalizowany.
  • zunifikowana pamięć współdzielona (unified shared memory, USM) ─ Dodatkowy model dostępu do tych samych danych zarówno przez hosta jak i akcelerator. Opiera się o wspólną dla CPU i akceleratora wirtualną przestrzeń adresową, oraz automatyczne transfery pamięci. Udostępnia także, podobne do CUDA, mechanizmy do ręcznego sterowania transferami pomiędzy akceleratorem a hostem (lub pomiędzy akceleratorami).
  • element i grupa robocza (work-item, work-group) ─ Podstawowe poziomy organizacji równoległych obliczeń na akceleratorze:
    • element roboczy (work-item) reprezentuje pojedynczą instancję kernela,
    • grupa robocza (work-group) reprezentuje grupę elementów roboczych wykonujących ten sam kernel, które posiadają dostęp do szybszej pamięci wspólnej oraz mogą być synchronizowane.
  • pamięć prywatna, lokalna oraz globalna (private, local, global memory) ─ Podstawowe rodzaje pamięci dostępne w kernelach:

    • prywatna ─ przeznaczona dla każdego z elementów roboczych z osobna,
    • lokalna ─ dostępna ze wszystkich elementów roboczych w danej grupie,
    • globalna ─ dostępna ze wszystkich elementów roboczych wykonujących dany kernel.

    Naturalnie im bliższa pamięć tym jest ona szybsza (dostęp ma najkrótsze opóźnienie), za to jej objętość jest mniejsza.

Informacje o standardzie

SYCL to stosunkowo młody standard (opublikowany w 2014 roku), powstał w ramach prac nad OpenCL jednak obecnie ewoluuje w sposób niezależny. Aktywnie rozwijany przez Khronos Group (konsorcjum odpowiedzialne za kilkanaście otwartych standardów). Dużej dynamiki rozwoju nadało wybranie SYCL przez firmę Intel jako bazowego rozwiązania dla swojej platformy oneAPI (opublikowanej w 2020 roku). Na ewolucję standardu ma również wpływ zbliżony koncepcyjnie model programowania Kokkos.

Obecna wersja to SYCL 2020 (poprzednia 1.2.1), która jest zgodna ze standardem C++17. Planowane jest opracowywanie kolejnych wersji równolegle do nowych wydań języka C++. Należy pamiętać, że SYCL jako standard nie posiada wzorcowego kompilatora. Realizacja jego założeń oraz stopień wdrożenia zależy od poszczególnych implementacji.

Rozwój standardu

rozwój SYCL w odniesieniu do standardu C++ oraz backendu OpenCL [źródło]

Aktualny standard nie jest jeszcze w pełni zaimplementowany, jednak aktywnie rozwijane główne implementacje (Intel DPC++ oraz AdaptiveCpp) systematycznie wdrażają nowe funkcjonalności. Często poszczególne implementacje dodają własne rozszerzenia do standardu. Dotyczą one zazwyczaj interoperacyjności pomiędzy różnymi typami akceleratorów lub obsługi specyficznych możliwości danego sprzętu. Niektóre z rozszerzeń mogą zostać włączone do oficjalnego standardu w kolejnych wersjach.

Przenośność kodu SYCL

Kod korzystający z podstawowych funkcjonalności zawartych w standardzie SYCL i nie korzystający z rozszerzeń powinien być przenośny pomiędzy implementacjami. Różnić może się natomiast proces kompilacji pod kątem konkretnej platformy sprzętowej.

Implementacje

SYCL jako rozwiązanie uniwersalne przyciąga uwagę szerokiego grona firm i badaczy. Dostępnych jest wiele implementacji. Można je podzielić na:

  • główne ─ najbardziej rozwinięte, nadające się do produkcyjnych rozwiązań i wspierające wiele akceleratorów;
  • pozostałe ─ często eksperymentalne implementacje, zazwyczaj skupiające się na pojedynczym rodzaju sprzętu.

Główne implementacje SYCL

główne implementacje SYCL [źródło]

Intel oneAPI DPC++

logo OneAPI

DPC++ (Data Parallel C++) to kompilator języka C++ rozszerzonego o SYCL rozwijany przez firmę Intel. Bazuje na platformie LLVM. Posiada własne rozszerzenia standardu SYCL. Wraz ze zbiorem bibliotek oraz narzędzi Intel oneAPI stanowi podstawowe środowisko do tworzenia oprogramowania akcelerowanego na platformy Intel (CPU, FPGA oraz wprowadzane układy GPU).

Intel wspiera również działania innych podmiotów mające na celu dodanie obsługi dla urządzeń innych producentów. Dzięki temu najnowsze wersje DPC++, poprzez wtyczki firmy Codeplay, pozwalają kompilować kod na urządzenia NVIDIA oraz AMD. Intel rozwija także narzędzia wspomagające migracje z CUDA do SYCL/DPC++ (więcej w sekcji Narzędzia️).

Intel DPC++ jest samodzielnym kompilatorem, a kompilacja na różne architektury sprowadza się zazwyczaj tylko do ustawienia odpowiedniej flagi kompilacji. Wydawany w ramach zestawu Intel oneAPI Base Toolkit (oraz HPC Toolkit), można go również pobrać osobno. Obecna wersja kompilatora to 2024.0 (Toolkit 2024.0), została wydana w listopadzie 2023 roku. Rocznie pojawiają się około 3 aktualizacje. Co warto dodać, kod źródłowy DPC++ jest publicznie dostępny, można go pobrać i samodzielnie skompilować.

Więcej informacji

AdaptiveCpp

logo AdaptiveCpp

AdaptiveCpp (dawniej hipSYCL oraz Open SYCL) to implementacja SYCL zapoczątkowana jako projekt badawczy na Heidelberg University, obecnie używana w środowiskach produkcyjnych i posiadająca oficjalne wsparcie Intela oraz SYCL Commitee z Khronos Group. Posiada najszersze wsparcie dla platform różnych producentów: GPU firm NVIDIA, AMD, Intel oraz CPU firm AMD, Intel i innych, dla których istnieje nowoczesny kompilator OpenMP.

W odróżnieniu od DPC++, AdaptiveCpp (acpp) nie jest samodzielnym kompilatorem, ale zbiorem bibliotek i pluginów do istniejących kompilatorów. Oznacza to, że na etapie kompilacji wymagana jest dostępność kompilatora oraz środowiska odpowiedniego dla wybranego schematu kompilacji (clang, nvc++, dpc++, gcc lub inne, oraz CUDA lub AMD ROCm).

Nową, unikalną dla AdaptiveCpp, funkcjonalnością jest tryb kompilacji SSCP (single-source, single compiler pass). Umożliwia on kompilację do specjalnego kodu pośredniego, który może być następnie, w tracie wykonywania programu, przetworzony do formatu pośredniego odpowiedniego dla architektury używanego akceleratora (PTX, amdgcn, SPIR-V). Umożliwia to uruchomienie jednej wersji skompilowanego programu na wszystkich wspieranych przez AdaptiveCpp platformach.

Inną z nowych funkcjonalności AdaptiveCpp jest możliwość delegowania (offloading) wykonania niektórych algorytmów biblioteki standardowej C++ do akceleratorów. Funkcjonalność ta jest realizowana poprzez tzw. execution policies i jest dostępna dla większości platform wspieranych przez AdaptiveCpp, w tym dla GPU NVIDIA, AMD oraz tych obsługiwanych przez mechanizm SSCP. Listę obsługiwanych algorytmów oraz inne szczegółowe informacje można znaleźć w dokumentacji opisującej wsparcie dla C++ standard parallelism.

Chociaż AdaptiveCpp rozwija się bardzo dynamicznie, nowe wersje nie są udostępniane regularnie. Ostatnia wersja to 23.10.0, wydana w październiku 2023. Przed zmianą nazwy projektu wersje były numerowane inaczej (ostatnia wersja w poprzedniej numeracji to hipSYCL 0.9.4 ze stycznia 2023). AdaptiveCpp udostępniany jest w formie kodu źródłowego, konieczna jest samodzielna instalacja.

Więcej informacji

Codeplay ComputeCpp

logo ComputeCpp

Jedna z pierwszych implementacji SYCL, zgodna ze standardem 1.2.1. Stworzona przez firmę Codeplay, której zamiar wykupienia Intel ogłosił w 2022 roku (firmy zawarły już stosowne porozumienie). Codeplay ma już na swoim koncie wkład w rozwój DPC++ w kierunku obsługi CUDA. ComputeCpp wspiera wąski zakres platform sprzętowych, nie należy spodziewać się nowszych wersji (obecna to 2.11).

Więcej informacji

Pozostałe implementacje

Pozostałe implementacje SYCL

pozostałe implementacje SYCL [źródło]

Spośród wielu innych implementacji SYCL, warto zwrócić uwagę na poniższe.

  • AMD triSYCL ─ Eksperymentalny, realizowany jako projekt badawczy przez firmę Xilinx (wykupioną w 2022 roku przez AMD) kompilator SYCL mający umożliwiać kompilacje na platformy FPGA AMD/Xilinx, głównie na akceleratory z linii Alveo. Nad projektem pracuje obecnie mała grupa deweloperów i jest on we wczesnej fazie rozwoju, udostępnia jednak wiele podstawowych funkcjonalności. Jedną z podejmowanych aktywności jest próba połączenia dotychczasowej implementacji triSYCL z dojrzałą implementacją DPC++ (patrz integracja z DPC++).
  • Celerity ─ Aktywnie rozwijana jako projekt badawczy biblioteka do obliczeń rozproszonych. Nie jest ściśle implementacją standardu SYCL, jednak poprzez bardzo podobne API umożliwia wykonywanie algorytmów zaimplementowanych w SYCL w środowiskach rozproszonych (wykorzystuje do tego MPI).

Narzędzia

  • Intel DPC++ Compatibility Tool (dpct) ─ Narzędzie wchodzące w skład pakietu Intel OneAPI umożliwiające automatyczne tłumaczenie kodu CUDA do postaci SYCL wspieranej przez DPC++.

Intel DPC++ Compatibility Tool

Intel DPC++ Compatibility Tool [źródło]

  • SYCLomatic (c2s) ─ Narzędzie do automatycznej migracji kodu CUDA do standardu SYCL. Jest to otwarto-źródłowa wersja DPC++ Compatibility Tool udostępniona przez Intel. Opis narzędzia można znaleźć w artykule "A New CUDA-to-SYCL Code Migration Tool".

Linki


  1. SYCL and the SYCL logo are trademarks of the Khronos Group Inc. 

  2. oneAPI to nie tylko nazwa pakietu oprogramowania firmy Intel ale również zbiór specyfikacji określających wymagania dla poszczególnych elementów pakietu. Pozwala to na mówienie o zgodności danej implementacji (nie tylko firmy Intel) z konkretną wersją standardu. Więcej – strona oneAPI oraz lista specyfikacji oneAPI


Ostatnia aktualizacja: 30 stycznia 2024