LINUX.ORG.RU

Почему Rust в 2 раза медленнее Си?

 , ,


0

5
% time ./c
./c  2.02s user 0.02s system 99% cpu 2.040 total
% time ./rust
./rust  4.84s user 0.04s system 99% cpu 4.886 total

Код на Си:

#include <stdio.h>

int slow_sqrt(int nbr)
{
	int i = 1;
	while (i < nbr)
	{
		if (nbr / i == i)
			{
				return i;
			}
		i++;
	}
	return 0;
}

int main(void)
{
	printf("Number %d", slow_sqrt(2147483646));
	return 0;
}

Код на Rust:

fn main() {
    let x: i32;
    x = slow_sqrt(2147483646);
    println!("Number {}", x);
}

fn slow_sqrt(nbr: i32) -> i32 {

    let mut i = 1;

    while i < nbr {
        if nbr / i == i
        {
            return i;
        }
        i += 1;
    }
    return 0;
}

По всей видимости Rust еще сырой язык для профессиональной разработки. Буду использовать Си.

просто замеры некорректны. Ни sqrt ни оптимизации не причём

Вы померили время загрузки/старта и завершения произвольной программы. У раст оно больше - его программы в силу объективных причин чуть дольше стартуют.

к тому у вас ещё вызов print померялся - в C это почти впрямую системный вызов write(), у раст до него через костыли и колдобины

MKuznetsov ★★★★★
()
Ответ на: комментарий от i-rinat

Погуглил оптимизации, попробовал с флагами которые в мануалах. Теперь Rust быстрее. Мда. Только начал Си понимать.

Видимо поэтому Rust в ядро добавляют, если он безопасный и быстрый, то смысл в Си отпадает.

cc -O2

1.36s user 0.01s system 88% cpu 1.547 total

rustc -O

1.34s user 0.01s system 99% cpu 1.355 total
avg_linux_enjoyer
() автор топика
Ответ на: комментарий от avg_linux_enjoyer

Теперь Rust быстрее. Мда. Только начал Си понимать.

Если нужно писать около-системщину с требованиями к безопасности и скорости — ZIG лучший кандидат нежели Rust. Думаю, через годик-другой стабилизируется и будет прелесть. В прочем, некоторым это не мешает уже сейчас писать серьезные вещи по типу Bun.

iron ★★★★★
()
Ответ на: комментарий от avg_linux_enjoyer

Я, конечно не программер, но иногда для оптимизации в циклах счетчик лучше объявлять как регистровую переменную:

register int i = 1;
Итого у меня получилось:

C:
5.990u 0.000s 0:05.99 100.0%	5+167k 0+0io 0pf+0w
rust:
8.000u 0.007s 0:08.00 100.0%	305+168k 0+0io 0pf+0w

$ cc -v
FreeBSD clang version 16.0.6 (https://github.com/llvm/llvm-project.git llvmorg-16.0.6-0-g7cbf1a259152)
Target: x86_64-unknown-freebsd13.2
Thread model: posix
InstalledDir: /usr/bin

$ rustc -V
rustc 1.71.0 (7bb61853a 2023-07-10) (built from a source tarball)
iron ★★★★★
()

2.02s 4.84s

FWIW, у меня получилось (single user, rtprio, best of 3)

  • clang 14 (-O3) 5.1 сек
  • rust 1.72 (-Copt-level=3) 5.1 сек
  • gcc 12 (-O3) - 5.5 сек

По всей видимости Rust еще сырой язык для профессиональной разработки. Буду использовать Си.

По твоей логике, если C - язык для профессиональной разработки, то ты как раз должен был выбрать «сырой Rust», потому из тебя, не знающего про флаги компиляторов и делающего выводы о языке по производительности одного синтетического теста, ещё и криво написанного, ещё и криво измеренной, профессионал как из говна пуля.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 1)
Ответ на: комментарий от iron
Ответ на: комментарий от avg_linux_enjoyer

Это здорово, что ты нашел где оптимизации включать. Но, позволь дать совет. Не используй rustc напрямую. У тебя специально в стандартном наборе идет cargo, который тебе и флаги включит, и зависимости правильных версий скачает, и инкрементальную сборку проведет.

Aswed ★★★★★
()
Ответ на: комментарий от MKuznetsov

Вы померили время загрузки/старта и завершения произвольной программы. У раст оно больше - его программы в силу объективных причин чуть дольше стартуют.

мне кажется при цифрах в 2сек и 4 можно пренебречь временем загрузки/старта.

ergo ★★★
()
Ответ на: комментарий от dup

Увы, Си != ассемблер. Например, на чистом Си не написать операционку, приходится использовать ассемблерные вставки. Но Си опирается на информационную модель приложения в памяти, это его роднит с ассемблером и процессорными командами, но друг друга они полностью заменить не смогут.

Vic
()
Ответ на: комментарий от Vic

на чистом Си не написать операционку, приходится использовать ассемблерные вставки.

Какую операционку?

это его роднит с ассемблером и процессорными командами, но друг друга они полностью заменить не смогут.

Как деды обходились без ассемблеров?

vM ★★
()
Последнее исправление: vM (всего исправлений: 1)
Ответ на: комментарий от vM

Какую операционку?

Любую, какую захочется сейчас или в будущем. Вместо операционки можно и другие специфичные вещи найти, просто операционка как более понятный и известный всем пример.

Как деды обходились без ассемблеров?

Страдали, конечно, поэтому, очень быстро придумали всякие ассемблеры.

Vic
()
Ответ на: комментарий от mx__

Можно, если выбран один критерий сравнения, которому они оба удовлетворяют. Тут же сравнивают не возможности языков по оформлению исходного кода.

Vic
()
Ответ на: комментарий от Vic

очень быстро придумали всякие ассемблеры

А потом всякие АЛГОЛы с ФОРТРАНами. А до ассемблеров Plankalkülи. И как-то обходились языками более высокого уровня. Даже чуть гордились своими безассемблерными вычислительными системами.

vM ★★
()

Жирный вброс жирного тролля. По всей видимости ты ещё сырой для местного общества. Да хоть на камнях считай, проблемы существующие только в твоей голове - проблемы только твоей головы :)

$ ls
Cargo.lock  Cargo.toml  foo  foo.c  foo.rs
$ cat Cargo.lock 
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3

[[package]]
name = "foo"
version = "0.1.0"
$ cat Cargo.toml 
[package]
name = "foo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[[bin]]
name = "foo-rs"
path = "foo.rs"
$ cat foo.c
#include <stdio.h>

int slow_sqrt(int nbr)
{
	int i = 1;
	while (i < nbr)
	{
		if (nbr / i == i)
			{
				return i;
			}
		i++;
	}
	return 0;
}

int main(void)
{
	printf("Number %d", slow_sqrt(2147483646));
	return 0;
}
$ cat foo.rs 
fn main() {
    let x: i32;
    x = slow_sqrt(2147483646);
    println!("Number {}", x);
}

fn slow_sqrt(nbr: i32) -> i32 {

    let mut i = 1;

    while i < nbr {
        if nbr / i == i
        {
            return i;
        }
        i += 1;
    }
    return 0;
}
$ gcc -O2 -march=native foo.c -o foo
$ time ./foo
Number 0
real	0m7.488s
user	0m7.484s
sys	0m0.002s
$ rm foo
$ gcc -O2 foo.c -o foo
$ time ./foo
Number 0
real	0m7.463s
user	0m7.461s
sys	0m0.001s
$ rm foo
$ gcc -O3 foo.c -o foo
$ time ./foo
Number 0
real	0m7.462s
user	0m7.461s
sys	0m0.001s
$ rm foo
$ gcc -O3 -march=native foo.c -o foo
$ time ./foo
Number 0
real	0m7.452s
user	0m7.450s
sys	0m0.002s
$ cargo build --release
   Compiling foo v0.1.0 (/var/home/user/foo)
    Finished release [optimized] target(s) in 0.19s
$ time ./target/release/foo-rs 
Number 0

real	0m7.454s
user	0m7.444s
sys	0m0.003s
anonymous-angler ★☆
()
Ответ на: комментарий от Aswed

А при zig все будет збс.

та падажжи, предыдущий збс еще в пути, в смысле на раст еще не все переписали, а ты уже зиг.

спокойно, плавно, равномерно, не надо нервировать население

olelookoe ★★★
()

тут вон и более интересное заявление что от register что-то зависит, перебрал кучу ключей на gcc11 и gcc12 и clang-14, у меня разницы нет

zurg
()
Ответ на: комментарий от Vic

На B, который уже был. Рабочее название будущего C было Next B.

По мере готовности автор https://github.com/dmr-1941-2011 переписывал компилятор на новом C.

https://www.tuhs.org/cgi-bin/utree.pl?file=V2/c/nc0/c00.c

https://github.com/dspinellis/unix-history-repo/blob/Research-V2-Snapshot-Development/c/nc0/c00.c

База: машинные коды

А при разработке аппаратуры машин, которая будут выполнять эти машинные коды, сейчас разве не используются высокоуровневые инструменты?

vM ★★
()
Ответ на: комментарий от vM

На B, который уже был. Рабочее название будущего C было Next B.

А «B» на чем написали?

А при разработке аппаратуры машин, которая будут выполнять эти машинные коды, сейчас разве не используются высокоуровневые инструменты?

Конечно используются, глупо же не пользоваться тем, что уже есть. Всё новое базируется на готовом современном, а особенно быстро идет смена в сфере разработки программ - условный компилятор «новый си» сейчас могут написать хоть на шарпе, хоть на яве, хоть на питное, хоть на имеющемся «си». Потом, со временем, «новый си» научится собирать сам себя и станет готовым текущим инструментом, на базе которого еще-что-то сделают. И т.д. Это же очевидно. А в чем собственно у тебя вопрос?

Vic
()
Ответ на: комментарий от Vic

«B» на чем написали?

Перед тем, как переписать «B» на «B», Кен Томпсон получил первую версию B с помощью высокоуровневого генератора трансляторов TMG.

https://www.multicians.org/tmg.html

А TMG в UNIX, согласно анектдоту, M. Douglas McIlroy принёс на листочках с работы над большими языками для больших систем.

В известных и не очень исторических статьях можно об этом прочитать.

https://www.cs.dartmouth.edu/~doug/reader.pdf

https://www.bell-labs.com/usr/dmr/www/chist.html

vM ★★
()
Ответ на: комментарий от vM

Перед тем, как переписать «B» на «B», Кен Томпсон получил первую версию B с помощью высокоуровневого генератора трансляторов TMG.

А TMG (и UNIX, раз уж TMG в UNIX) на чем написали?

PS. Вы же понимаете, что до ассемблера мы все-таки дойдем.

PPS. За замечательные ссылки примите отдельную благодарность!

Vic
()
Ответ на: комментарий от Vic

Текст самого TMG, написанный на самом TMG, можно увидеть, пройдя по одной из замечательных ссылок из моего предыдущего сообщения https://www.multicians.org/tmg.html

PS к ответу на вопрос не относится, не успел добавить ссылку в предыдущее сообщение https://man.cat-v.org/unix-6th/6/tmg как напоминание о том, почему же юниксовый yacc называется yet another cc

vM ★★
()
Ответ на: комментарий от vM

Текст самого TMG, написанный на самом TMG …

Ну, был же момент времени, когда еще не было TMG, и его на чем-то начали делать, так ведь?

PS. Я вам просто гарантирую, что до ассемблера дойдем. Или до машинных кодов дойдем, если разработчики TMG писали его без ассемблера, в чем я очень сомневаюсь, ибо вот что есть по вашей ссылочке (https://www.multicians.org/tmg.html):

FILES

name.s: assembly language version of name.t
Vic
()
Последнее исправление: Vic (всего исправлений: 2)
Ответ на: комментарий от Vic

Дойдём и до sh, и до ed, и, наконец, до as, но это уже после того, как M. Douglas McIlroy написал на листочке бумаги на языке TMG траслятор с TMG на входной язык as PDP-7 UNIX без компьютера. И без компьютера вручную странслировал его, выполнив правила TMG, которые он на этом листочке написал.

Изначальный TMG был написан изначальным автором на более или менее обычном языке высокого уровня TMGL. Он не мог быть написан на входном языке юниксового as для PDP-7, потому что тогда ни as, ни самого UNIX’a ещё не было. И ничего платформоориентированного в TMG нет. TMG – системное программное обеспечение, но высокоуровневое.

Много позже, где-то ближе ко временам шестого издания, McIlroy написал уже на PDP-11 с использованием as реализацию new TMG. Но вскоре Stephen C. Johnson использовал Си для Yet Another Compiler-Compiler и с седьмого издания UNIX остался только yacc. https://www.cs.utexas.edu/users/novak/yaccpaper.htm

vM ★★
()
Ответ на: комментарий от vM

И без компьютера вручную странслировал его

В машинные коды?

Так то ассемблер тоже может себя скомпилировать, да и вручную его тоже можно странслировать в машинные коды.

Но обычно какой-то ассемблер делают в первую очередь, т.к. он позволяет сделать запись программы в, по сути в машинных кодах, не позволяя никаких автоматических вольностей и не допуская никаких оптимизаций, которые присущи языкам более высокого уровня (включая язык Си).

Т.е. как написал в ассемблере, так будет и в машинных кодах, поэтому, ассемблер ни чем не заменим. Это, конечно, не означает, что надо все и вся делать на ассемблере, а только то и там где это имеет смысл.

PS. YACC - это вообще вспомогательная вещь для облегчения процесса разработки компиляторов в начальных их фазах (парсинг, лексемы, и т.п.). Пока до него дошли, наверняка, каждый запилил не один вариант таких вспомогательных инструментов.

Vic
()
Последнее исправление: Vic (всего исправлений: 1)
Ответ на: комментарий от vM

Даже если сам ассемблер написан на ФОРТРАНе ?

Так, конечно нет, ассмблер же не парсит язык и модель фортрана.

Но тогда возникают следующие вопросы:

  • На чем изначально написан сам фортран, на котором написан ассемблер?
  • Зачем на фортране написали ассемблер? Фортрана в чем-то не хватает (например, операционка не получается на чистом фортране без ассемблерных вставок)?

Просьба учесть, что мы ведем речь в контексте вот этого исходного сообщения (ссылка на сообщение), где на начальном этапе у нас есть только «машинные коды», и наша цель сделать компилятор, который будет и сам работать и код генерировать на том же целевом процессоре.

А что делать при смене процессора (процессор с новым набором команд), но имея рабочий компилятор на любом другом процессоре, вполне очевидно — в имеющийся компилятор можно добавить кросс-компиляцию в новый целевой процессор и скомпилировать сам компилятор для новой платформы и уже новый скомпилированный компилятор адаптировать к целевой платформе. Т.е. с переносом чего-то готового, на новый процессор, особых проблем нет.

Есть еще компиляторы, которые не предполагают переноса на целевой процессор, например, компилятор для малых процессоров типа Pic или ATTiny. Запускать сам компилятор в этих процессорах не имеет смысла, слишком мало там аппаратных ресурсов. Этот кейс мы тоже не рассматриваем, т.к. он тривиален.

Vic
()
Последнее исправление: Vic (всего исправлений: 5)
Ответ на: комментарий от Vic

на чем изначально написан сам фортран, на котором написан ассемблер?

Какое это имеет значение для того, кто сделал ассемблер на ФОРТРАНе? Он не знает о том, как реализован ForTran у пользователей его ассемблера.

Зачем на фортране написали ассемблер?

Зачем на Си написали the GNU Assembler во второй половине 1980-х ?

https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gas/write.c;h=a0b36c35173c2c48288dfb33c80919777fb0a5be;hb=fecd2382e77b89f12c9d630ed4e42e9a54ba6953

Разработчики микропроцеесорного комплекта написали свой на FORTRAN-66 (a.k.a. FORTRAN IV), чтобы разработчик микропроцессорного устройства мог пользоваться ассемблером на доступной ему ЭВМ третьего поколения общего назначения, на которой есть FORTRAN, соответствующий стандарту. Или подключиться к условной CompuServ и использовать там готовый ассемблер. И в итоге получить перфоленту прошивки, которую можно отправить изготовителю масочных ПЗУ для монтажа в готовые экземпляры устройства или загрузить промежуточный вариант в отладочную систему для тестирования и наладки.

мы ведем речь в контексте вот этого исходного сообщения… на начальном этапе у нас есть только «машинные коды», и наша цель сделать компилятор, который будет и сам работать и код генерировать на том же целевом процессоре.

Но недоступность других вычислительных систем не соответствует ни историческому контексту, в котором развивался Си в 1970-х, ни условиям, в которых зародилась будущая UNIX в самом конце 1960-х. Тем более это не соответсвует контексту, в котором появился обсуждаемый Rust.

vM ★★
()
Ответ на: комментарий от vM

Зачем на Си написали the GNU Assembler во второй половине 1980-х ?

Потому что так удобнее, т.к. компилятор Си уже был. Это же очевидно.

Но недоступность других вычислительных систем не соответствует ни историческому контексту, в котором развивался Си в 1970-х, ни условиям, в которых зародилась будущая UNIX в самом конце 1960-х. Тем более это не соответствует контексту, в котором появился обсуждаемый Rust.

Обсуждение началось с данного сообщения (ссылка на сообщение, где «си != ассемблер»), и что без ассемблера нельзя написать операционку, а так же, то, что после машинных кодов появляется ассемблер (ссылка на сообщение, где «База: машинные коды -> ассемблер -> ..»), который предшествовал любому, самому первому языку программирования.

Исторические справки по конкретным языкам приводите только вы. Это познавательно и полезно, но не имеет прямого отношения к теме (которая уже давно в превратилась в оффтоп и не относится к расту).

Vic
()
Ответ на: комментарий от Vic

«си != ассемблер»

Разве это не очевидно?

ассемблер … предшествовал любому, самому первому языку программирования.

Это исторически не так. Ассемблеры стали использовать позже других утилит, облегчающих программирование и отладку. И после того, как первые программы были написаны на других языках программирования.

А практическая необходимость использования ассемблеров явилась ещё чуть позже.

без ассемблера нельзя написать операционку

В чём содержание и границы понятия операционка? И что препятствует использованию языков программирования высокого уровня при создании и доработке операционок?

vM ★★
()
Ответ на: комментарий от vM

«си != ассемблер»

Разве это не очевидно?

Автор вопроса интересовался.

ассемблер … предшествовал любому, самому первому языку программирования.

Это исторически не так.

Так. Язык ассемблера, это запись машинных кодов (чисел ,которые исполнит процессор) в виде легко запоминающихся и понятных команд (мнемоника). Человеку так проще описывать программу, а программа, переводящая запись в машинные коды достаточно проста. Зачастую еще нет реального процессора в железе, а мнемоника команд будущего процессора уже есть на бумаге и уже пишут компилятор ассемблера для него.

Кроме того, язык ассемблера, это единственный язык, в котором каждая ассемблерная команда соответствует одной команде процессора. Последовательность ассемблерных команд в точности совпадает с последовательностью команд процессору в машинных кодах.

Поэтому, никакой другой язык не заменит языки ассемблера.

без ассемблера нельзя написать операционку

В чём содержание и границы понятия операционка?

Обычные, общечеловеческие границы и понятия. И что бы не вдаваться в крайности, которые я у вас замечаю, сразу скажу, что операционки пишутся не полностью на ассемблере, даже наоборот, чем меньше ассемблера в операционке, тем лучше. Но, без ассемблера никак.

И что препятствует использованию языков программирования высокого уровня при создании и доработке операционок?

Наличие дополнительных абстракций, которых в процессорах нет и которые процессорам чужды.

Были попытки сделать JAVA процессор, но, оказалось, что без классического адресного пространства, прерываний, регистров аппаратуры и т.п. далеко не уедешь. А тащить все это многообразие внутрь процессора (внутрь JAVA машины) очень трудоемко, но не с точки зрения реализации, а сточки зрения сопряжения процессора с различными внешними к процессору устройствами.

Vic
()
Ответ на: комментарий от Vic

каждая ассемблерная команда соответствует одной команде процессора

Это некорректное утверждение. Корректное утверждение - «одна ассемблерная комманда компилируется в одну инструкцию процессора»

FishHook
()