Эльбрус/llvm: различия между версиями

Материал из ALT Linux Wiki
(создана страница, написано про llvm, clang, llvm-cbe)
 
м (начальные сведения по llvm13)
 
(не показаны 2 промежуточные версии 2 участников)
Строка 1: Строка 1:
== LLVM ==
== LLVM ==


В современных версиях ОС Эльбрус имеется LLVM 9, который может собирать код не только для платформ AMDGPU и, с недавнего времени, NVPTX (nVidia), но и для e2k. К примеру, для ОС Эльбрус 6.0.1:
В современных версиях [http://mcst.ru/elbrus_linux ОС Эльбрус] имеется LLVM 9 (начиная с OSL 7.2 -- и llvm13), который может собирать код не только для платформ AMDGPU и с недавнего времени NVPTX (nVidia), но и для e2k. К примеру, для ОС Эльбрус 6.0.1:


     molchan_i@yukari ~ $ head -n1 /etc/mcst_version
     molchan_i@yukari ~ $ head -n1 /etc/mcst_version
Строка 12: Строка 12:
== clang ==
== clang ==


В состав ОС Эльбрус также входит clang как альтернатива lcc, который также умеет собирать ПО под Эльбрус.
В состав ОС Эльбрус также входит clang как экспериментальная альтернатива lcc, который также в некотором смысле умеет собирать ПО под Эльбрус. На данный момент он не считается доведённым до финала разработки и может быть использован на собственный страх и риск пользователя, но в некоторых случаях может оказаться предпочтителен (например, telegram-desktop 3.2 не удалось собрать lcc 1.25, в отличие от clang 9.0.1; при этом версию 4.3 собрали lcc 1.26).


Для примера - сборка архиватора plzip:
Для примера - сборка архиватора plzip:
Строка 27: Строка 27:
     dd if=/dev/urandom of=testfile count=1k bs=1k
     dd if=/dev/urandom of=testfile count=1k bs=1k


3. Сборка:
3.1. Сборка (-O2):


     cd lzlib-1.12
     cd lzlib-1.12
Строка 33: Строка 33:
     make -j4
     make -j4
     cd ../plzip-1.9
     cd ../plzip-1.9
     ./configure CXX=clang++ CXXFLAGS=-I../lzlib-1.12 LDFLAGS=-L../lzlib-1.12
     ./configure CXX=clang++ CXXFLAGS="-O2 -I../lzlib-1.12" LDFLAGS=-L../lzlib-1.12
     make -j8
     make -j8


4. Запуск:
3.2. Запуск (-O2):


     molchan_i@yukari ~/clang-demo/plzip-1.9 $ time ./plzip -fvk9 ../testfile
     molchan_i@yukari ~/clang-demo/plzip-1.9 $ time ./plzip -fvk9 ../testfile
       ../testfile:  0.987:1, 101.37% ratio, -1.37% saved, 1048576 in, 1062911 out.
       ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
      
      
     real    0m2,287s
     real    0m2,165s
     user    0m2,280s
     user    0m2,071s
     sys    0m0,010s
     sys    0m0,101s


Для сравнения, тот же plzip, но собранный без указания CC=clang и CXX=clang++ (то есть, штатным lcc):
Потом делаем <code>cd ..</code>.
 
4.1. Сборка (-O4):
 
    cd lzlib-1.12
    ./configure CC=clang CFLAGS="-O4"
    make -j4
    cd ../plzip-1.9
    ./configure CXX=clang++ CXXFLAGS="-O4 -I../lzlib-1.12" LDFLAGS=-L../lzlib-1.12
    make -j8
 
4.2. Запуск (-O4):
 
    molchan_i@yukari ~/clang-demo/plzip-1.9 $ time ./plzip -fvk9 ../testfile
      ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
    real    0m2,390s
    user    0m2,308s
    sys    0m0,091s
 
Потом делаем <code>cd ..</code>.
 
Вывод: указание оптимизаций не влияет на быстродействие (результат на -O4 оказался даже хуже).
 
Для сравнения, тот же plzip, но собранный без указания <code>CC=clang</code> и <code>CXX=clang++</code> (то есть, штатным lcc):
 
В режиме -O2:


     molchan_i@yukari ~/clang-demo/plzip-1.9-lcc $ time ./plzip -fvk9 ../testfile
     molchan_i@yukari ~/clang-demo/plzip-1.9-lcc $ time ./plzip -fvk9 ../testfile
       ../testfile:  0.987:1, 101.37% ratio, -1.37% saved, 1048576 in, 1062911 out.
       ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
      
      
     real    0m0,823s
     real    0m0,811s
     user    0m0,800s
     user    0m0,743s
     sys    0m0,030s
     sys    0m0,070s


Видно, что из коробки без настроек lcc даёт код, работающий быстрее в 2,5-3 раза, но когда что-то не собирается lcc (но при этом собирается clang-ом) - это хотя бы даёт возможность собрать и запустить что-то, что хочется запустить на эльбрусе.
В режиме -O4:
 
    molchan_i@yukari ~/clang-demo/plzip-1.9-lcc $ time ./plzip -fvk9 ../testfile
      ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
    real    0m0,692s
    user    0m0,598s
    sys    0m0,101s
 
Видно, что из коробки без настроек lcc даёт код, работающий быстрее в 2,7-3,5 раза, но когда что-то не собирается lcc (но при этом собирается clang-ом) - это хотя бы может дать возможность собрать и запустить что-то, что хочется запустить на эльбрусе.


== llvm-cbe ==
== llvm-cbe ==
Строка 132: Строка 167:
     done
     done


Из за нескольких проблем (issue [https://github.com/JuliaComputingOSS/llvm-cbe/issues/132 132], [https://github.com/JuliaComputingOSS/llvm-cbe/issues/133 133], [https://github.com/JuliaComputingOSS/llvm-cbe/issues/134 134], [https://github.com/JuliaComputingOSS/llvm-cbe/issues/138 138]) llvm-cbe не может собрать всё целиком, поэтому для исходников plzip приходится использовать обычный gcc.
Из за нескольких проблем (issue [https://github.com/JuliaComputingOSS/llvm-cbe/issues/132 132], [https://github.com/JuliaComputingOSS/llvm-cbe/issues/133 133], [https://github.com/JuliaComputingOSS/llvm-cbe/issues/134 134], [https://github.com/JuliaComputingOSS/llvm-cbe/issues/138 138]) llvm-cbe не может собрать всё целиком, поэтому для исходников plzip приходится использовать обычный gcc/lcc.


Видим, что все собранные plzip-ы отработали нормально.
Видим, что все собранные plzip-ы отработали нормально.


4. И наконец, с учётом полученной информации, собираем под эльбрус. LCC не понимает комментария препроцессора "line 0", поэтому в CBE-выхлопе его надо заменять:
5. И наконец, с учётом полученной информации, собираем под эльбрус. LCC не понимает комментария препроцессора "line 0", поэтому в CBE-выхлопе его надо заменять:


     git clone https://github.com/JuliaComputing/llvm-cbe
     git clone https://github.com/JuliaComputing/llvm-cbe
Строка 150: Строка 185:
      
      
     dd if=/dev/urandom of=testfile count=1k bs=1k
     dd if=/dev/urandom of=testfile count=1k bs=1k
   
    export OPT=-O2
      
      
     clang -S -emit-llvm -g lzlib-1.12/lzlib.c -Ilzlib-1.12 -o lzlib.ll
     clang -S -emit-llvm -g lzlib-1.12/lzlib.c -Ilzlib-1.12 -o lzlib.ll
     tools/llvm-cbe/llvm-cbe lzlib.ll
     tools/llvm-cbe/llvm-cbe lzlib.ll
     sed -i 's/#line 0/#line 1/' lzlib.cbe.c
     sed -i 's/#line 0/#line 1/' lzlib.cbe.c
     lcc -c -o lzlib.o lzlib.cbe.c
     lcc $OPT -c -o lzlib.o lzlib.cbe.c
      
      
     for src in arg_parser lzip_index list compress dec_stdout dec_stream decompress main
     for src in arg_parser lzip_index list compress dec_stdout dec_stream decompress main
     do
     do
         l++ -Iplzip-1.9 -Ilzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -c -o $src.o plzip-1.9/$src.cc
         l++ $OPT -Iplzip-1.9 -Ilzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -c -o $src.o plzip-1.9/$src.cc
     done
     done
      
      
     l++ arg_parser.o lzip_index.o list.o compress.o dec_stdout.o dec_stream.o decompress.o main.o lzlib.o -lpthread -o plzip
     l++ $OPT arg_parser.o lzip_index.o list.o compress.o dec_stdout.o dec_stream.o decompress.o main.o lzlib.o -lpthread -o plzip
     time ./plzip -fvk9 testfile
     time ./plzip -fvk9 testfile


Результаты:
Результаты (-O2):
 
    molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
      testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
    real    0m1,412s
    user    0m1,338s
    sys    0m0,081s
 
Результаты (-O4; для этого заменяем <code>export OPT=-O2</code> на <code>export OPT=-O4</code>):
 
    molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
      testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
    real    0m1,385s
    user    0m1,293s
    sys    0m0,081s
 
Результаты (без указания оптимизаций; для этого заменяем <code>export OPT=-O2</code> на <code>export OPT=</code>):


     molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
     molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
       testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062838 out.
       testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
      
      
     real    0m8,134s
     real    0m7,569s
     user    0m8,080s
     user    0m7,517s
     sys    0m0,060s
     sys    0m0,062s


Что ж, в 10 раз медленнее lcc, но иногда другого выхода нет.
Внезапно, с оптимизациями получилось даже быстрее, чем если собирать нативным clang-ом. А вот без оптимизаций результат в 10 раз медленнее нативного lcc.


{{Category navigation|title=E2K|category=E2K|sortkey=*}}
{{Category navigation|title=E2K|category=E2K|sortkey=*}}

Текущая версия от 16:00, 13 апреля 2023

LLVM

В современных версиях ОС Эльбрус имеется LLVM 9 (начиная с OSL 7.2 -- и llvm13), который может собирать код не только для платформ AMDGPU и с недавнего времени NVPTX (nVidia), но и для e2k. К примеру, для ОС Эльбрус 6.0.1:

   molchan_i@yukari ~ $ head -n1 /etc/mcst_version
   6.0.1
   molchan_i@yukari ~ $ llvm-config --version
   9.0.1
   molchan_i@yukari ~ $ llvm-config --targets-built
   Elbrus AMDGPU NVPTX

clang

В состав ОС Эльбрус также входит clang как экспериментальная альтернатива lcc, который также в некотором смысле умеет собирать ПО под Эльбрус. На данный момент он не считается доведённым до финала разработки и может быть использован на собственный страх и риск пользователя, но в некоторых случаях может оказаться предпочтителен (например, telegram-desktop 3.2 не удалось собрать lcc 1.25, в отличие от clang 9.0.1; при этом версию 4.3 собрали lcc 1.26).

Для примера - сборка архиватора plzip:

1. Выкачиваем исходники и распаковываем их:

   wget http://download.savannah.gnu.org/releases/lzip/lzlib/lzlib-1.12.tar.gz
   wget http://download.savannah.gnu.org/releases/lzip/plzip/plzip-1.9.tar.gz
   tar xf plzip-1.9.tar.gz
   tar xf lzlib-1.12.tar.gz

2. Создаём тестовый файл (заполненный рандомными значениями)

   dd if=/dev/urandom of=testfile count=1k bs=1k

3.1. Сборка (-O2):

   cd lzlib-1.12
   ./configure CC=clang
   make -j4
   cd ../plzip-1.9
   ./configure CXX=clang++ CXXFLAGS="-O2 -I../lzlib-1.12" LDFLAGS=-L../lzlib-1.12
   make -j8

3.2. Запуск (-O2):

   molchan_i@yukari ~/clang-demo/plzip-1.9 $ time ./plzip -fvk9 ../testfile
     ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m2,165s
   user    0m2,071s
   sys     0m0,101s

Потом делаем cd ...

4.1. Сборка (-O4):

   cd lzlib-1.12
   ./configure CC=clang CFLAGS="-O4"
   make -j4
   cd ../plzip-1.9
   ./configure CXX=clang++ CXXFLAGS="-O4 -I../lzlib-1.12" LDFLAGS=-L../lzlib-1.12
   make -j8

4.2. Запуск (-O4):

   molchan_i@yukari ~/clang-demo/plzip-1.9 $ time ./plzip -fvk9 ../testfile
     ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m2,390s
   user    0m2,308s
   sys     0m0,091s

Потом делаем cd ...

Вывод: указание оптимизаций не влияет на быстродействие (результат на -O4 оказался даже хуже).

Для сравнения, тот же plzip, но собранный без указания CC=clang и CXX=clang++ (то есть, штатным lcc):

В режиме -O2:

   molchan_i@yukari ~/clang-demo/plzip-1.9-lcc $ time ./plzip -fvk9 ../testfile
     ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m0,811s
   user    0m0,743s
   sys     0m0,070s

В режиме -O4:

   molchan_i@yukari ~/clang-demo/plzip-1.9-lcc $ time ./plzip -fvk9 ../testfile
     ../testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m0,692s
   user    0m0,598s
   sys     0m0,101s

Видно, что из коробки без настроек lcc даёт код, работающий быстрее в 2,7-3,5 раза, но когда что-то не собирается lcc (но при этом собирается clang-ом) - это хотя бы может дать возможность собрать и запустить что-то, что хочется запустить на эльбрусе.

llvm-cbe

Была попытка для сравнения использовать C-backend для LLVM - llvm-cbe.

Суть в том, что если штатный компилятор не может собрать исходный код (например, он ломается на этом коде, либо вообще нет компилятора для этого языка), мы преобразовываем исходный код в LLVM-IR, его с помощью llvm-cbe - в С-код (который сгенерён из LLVM-представления), а потом получившийся код собираем уже штатным С-компилятором.

Это выглядит примерно так:

   clang -S -emit-llvm -g входной_файл.c -o файл_llvm_представления.ll # Здесь может быть любой компилятор, генерирующий LLVM-IR-выхлоп (.ll-файл)
   llvm-cbe файл_llvm_представления.ll # Из *.ll будет создан *.cbe.c
   gcc -c -o выходной_объектный_файл.o файл_llvm_представления.cbe.c

На Intel-машине выяснено, что нынешний вариант умеет собираться только под LLVM 8, 9, 10 и 11 (6 и 7 слишком старые). Изначально он умел только в LLVM 10 и 11, но после принятия PR #131 LLVM 8-9 также починились. К счастью, на Эльбрусе есть LLVM 9.0.1, так что нам этого достаточно.

1. Выкачиваем исходники:

   git clone https://github.com/JuliaComputing/llvm-cbe
   cd llvm-cbe

2. Собираем для каждого из возможных LLVM и прогоняем unit-тесты

   for i in 8 9 10 11
   do
       echo -e "\n\e[1;33m************** $i ***************\n\e[0m"
       mkdir -p build-$i
       pushd build-$i
       cmake .. -DLLVM_DIR=/usr/lib/llvm-$i/cmake -DLLVM_INCLUDE_TESTS=1 && make -j16 llvm-cbe CBEUnitTests
       pushd unittests
       ./CWriterTest 
       popd
       popd
   done

3. Пробуем собрать и выполнить один из примеров (в ./main.cbe нужно будет ввести количество элементов и собственно сами элементы для сортировки):

   for i in 8 9 10 11
   do
       echo -e "\n\e[1;33m************** $i ***************\n\e[0m"
       pushd build-$i
       clang-$i -S -emit-llvm -g ../test/selectionsort/main.c
       tools/llvm-cbe/llvm-cbe main.ll
       gcc-10 -Wno-builtin-declaration-mismatch -o main.cbe main.cbe.c
       ./main.cbe
       rm -f main.ll main.cbe main.cbe.c
       popd
   done

4. Попытка собрать lzlib и plzip

   for i in 8 9 10 11
   do
       echo -e "\n\e[1;33m************** $i ***************\n\e[0m"
       pushd build-$i
   
       # Собираем объектник lzlib:
       clang-$i -S -emit-llvm -g ../lzlib-1.12/lzlib.c -I../lzlib-1.12 -o lzlib.ll
       tools/llvm-cbe/llvm-cbe lzlib.ll
       gcc-10 -Wno-builtin-declaration-mismatch -c -o lzlib.o lzlib.cbe.c
   
       # Собираем plzip (вручную):
       for src in arg_parser lzip_index list compress dec_stdout dec_stream decompress main
       do
   #        Увы, из-за issue-в, указанных ниже, собрать через llvm-cbe нельзя - собираем с помощью gcc
   #        clang++-$i -S -emit-llvm -g -I../plzip-1.9 -I../lzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -o $src.ll ../plzip-1.9/$src.cc
   #        tools/llvm-cbe/llvm-cbe $src.ll
   #        gcc-10 -Wno-builtin-declaration-mismatch -Wno-address-of-packed-member -c -o $src.o $src.cbe.c
           gcc -I./plzip-1.9 -I../lzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -c -o $src.o ../plzip-1.9/$src.cc
       done
   
       # Линкуемся с в том числе lzlib.o:
       g++ arg_parser.o lzip_index.o list.o compress.o dec_stdout.o dec_stream.o decompress.o main.o lzlib.o -lpthread -o plzip
       ./plzip -kv ../testfile -o testfile-$i.lz
       ./plzip -tv testfile-$i.lz
       popd
   done

Из за нескольких проблем (issue 132, 133, 134, 138) llvm-cbe не может собрать всё целиком, поэтому для исходников plzip приходится использовать обычный gcc/lcc.

Видим, что все собранные plzip-ы отработали нормально.

5. И наконец, с учётом полученной информации, собираем под эльбрус. LCC не понимает комментария препроцессора "line 0", поэтому в CBE-выхлопе его надо заменять:

   git clone https://github.com/JuliaComputing/llvm-cbe
   cd llvm-cbe
   mkdir -p build
   cd build
   cmake .. && make -j16 llvm-cbe
   
   wget http://download.savannah.gnu.org/releases/lzip/lzlib/lzlib-1.12.tar.gz
   wget http://download.savannah.gnu.org/releases/lzip/plzip/plzip-1.9.tar.gz
   tar xf plzip-1.9.tar.gz
   tar xf lzlib-1.12.tar.gz
   
   dd if=/dev/urandom of=testfile count=1k bs=1k
   
   export OPT=-O2
   
   clang -S -emit-llvm -g lzlib-1.12/lzlib.c -Ilzlib-1.12 -o lzlib.ll
   tools/llvm-cbe/llvm-cbe lzlib.ll
   sed -i 's/#line 0/#line 1/' lzlib.cbe.c
   lcc $OPT -c -o lzlib.o lzlib.cbe.c
   
   for src in arg_parser lzip_index list compress dec_stdout dec_stream decompress main
   do
       l++ $OPT -Iplzip-1.9 -Ilzlib-1.12 -DPROGVERSION='"1.9-llvm-cbe"' -c -o $src.o plzip-1.9/$src.cc
   done
   
   l++ $OPT arg_parser.o lzip_index.o list.o compress.o dec_stdout.o dec_stream.o decompress.o main.o lzlib.o -lpthread -o plzip
   time ./plzip -fvk9 testfile

Результаты (-O2):

   molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
     testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m1,412s
   user    0m1,338s
   sys     0m0,081s

Результаты (-O4; для этого заменяем export OPT=-O2 на export OPT=-O4):

   molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
     testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m1,385s
   user    0m1,293s
   sys     0m0,081s

Результаты (без указания оптимизаций; для этого заменяем export OPT=-O2 на export OPT=):

   molchan_i@yukari ~/clang-demo/llvm-cbe/build $ time ./plzip -fvk9 testfile
     testfile:  0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out.
   
   real    0m7,569s
   user    0m7,517s
   sys     0m0,062s

Внезапно, с оптимизациями получилось даже быстрее, чем если собирать нативным clang-ом. А вот без оптимизаций результат в 10 раз медленнее нативного lcc.