Эльбрус/llvm: различия между версиями
(создана страница, написано про llvm, clang, llvm-cbe) |
м (начальные сведения по llvm13) |
||
(не показаны 2 промежуточные версии 2 участников) | |||
Строка 1: | Строка 1: | ||
== LLVM == | == LLVM == | ||
В современных версиях ОС Эльбрус имеется LLVM 9, который может собирать код не только для платформ AMDGPU и | В современных версиях [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 | ||
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. | ../testfile: 0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out. | ||
real 0m2, | real 0m2,165s | ||
user 0m2, | user 0m2,071s | ||
sys 0m0, | 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. | ../testfile: 0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out. | ||
real 0m0, | real 0m0,811s | ||
user 0m0, | user 0m0,743s | ||
sys 0m0, | sys 0m0,070s | ||
Видно, что из коробки без настроек lcc даёт код, работающий быстрее в 2, | В режиме -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-ы отработали нормально. | ||
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, | testfile: 0.987:1, 101.36% ratio, -1.36% saved, 1048576 in, 1062887 out. | ||
real | real 0m7,569s | ||
user | user 0m7,517s | ||
sys 0m0, | sys 0m0,062s | ||
Внезапно, с оптимизациями получилось даже быстрее, чем если собирать нативным 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.