вторник, 9 июня 2009 г.

про интернет в Калифорнии (продолжение...)

Сегодня прихожу на рабочее место - смотрю какой-то мужичек возле моего ноута крутиться.
- Вотс гоин он? говорю.
Он отвечает на чистейшем американском - а это ваш компьютер?
- Мой - говорю.
- А вы ничего большого не качали? - спрашивает он, видимо в надежде на отмазки.
- Качал говорю - не далее как в конце прошлой недели - 8 Гб за вечер утянул в торрентах с сайта Fedoraproject.org
- Ну вообщем-то говорит не большая проблема, просто вы канал нам просадили на прошлой недели в усмерть - никто работать не мог. Я - говорит - грешным делом на порновирус рассчитывал - а тут вы со своим Линуксом.
- Да - говорю я, не извиняясь - херня такая этот Линукс - говорю смотри - апдэйтов кажет 686 штук и показал значек ПэкаджКита. Хотя - говорю - на прошлой неделе не менее после установки вытянул...
- А ограничить по полосе его нельзя?
- Да можно, тока я думал у вас в Америке с пропускной способностью каналов проблем нет, начал я испорченный Иллинойсовским безлимитом на комкасте....
- Не делайте так больше - сказал мужик и ушел...

Вот такая вот поучительная история...
Походу тут каналы в Силиконке нифига не широкие...
И "палят" на них реально...

C++ для встроенного ПО

Читаю статью на Руководство по С++ для осмотрительного программера встроенных систем на embedded.com.

Прежде всего, хочеться отметить, что мне понравился сайт, как ресурс. Я давно на него поглядывал, но все не находил времени почитать. Интересные советы, статьи. Нельзя сказать, что все новое и незнакомое - где-то слышал то, где-то это...

Вообщем, иногда имеет смысл поглядывать, и не забывать.

Решил немного посчитать и поэкспериментировать.

Написал маленький и смешной кусок кода:

int main(int argc, char * argv[])
{
return 0;
}


скопировал текст в два файла:
try_me.c
try_me.cpp

собрал "в лоб" по простому...

[snikulov@solarwind c_vs_cpp]$ gcc try_me.c -o try_c
[snikulov@solarwind c_vs_cpp]$ g++ try_me.cpp -o try_cpp
[snikulov@solarwind c_vs_cpp]$ ls -la
total 32
drwxrwxr-x. 2 snikulov snikulov 4096 2009-06-08 23:28 .
drwxrwxr-x. 6 snikulov snikulov 4096 2009-06-08 22:41 ..
-rwxrwxr-x. 1 snikulov snikulov 4728 2009-06-08 23:27 try_c
-rwxrwxr-x. 1 snikulov snikulov 5047 2009-06-08 23:27 try_cpp
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.c
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.cpp
[snikulov@solarwind c_vs_cpp]$

Ну что тут сказать - 4728 vs. 5047

Вообщем C++ вариант больше на 300 байт просто без всего.

Играемся с опциями компилятора (пока по размеру -Os):

[snikulov@solarwind c_vs_cpp]$ g++ try_me.cpp -Os -o try_cpp
[snikulov@solarwind c_vs_cpp]$ gcc try_me.c -Os -o try_c
[snikulov@solarwind c_vs_cpp]$ ls -la
total 32
drwxrwxr-x. 2 snikulov snikulov 4096 2009-06-08 23:33 .
drwxrwxr-x. 6 snikulov snikulov 4096 2009-06-08 22:41 ..
-rwxrwxr-x. 1 snikulov snikulov 4728 2009-06-08 23:33 try_c
-rwxrwxr-x. 1 snikulov snikulov 5047 2009-06-08 23:33 try_cpp
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.c
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.cpp
[snikulov@solarwind c_vs_cpp]$

Эффекта не замечаем - предполагаю что компилер оптимизирует (означает что оптимизировать там нечего ;-) )

Ок. Переходим к отключению фич языка C++ - это должно быть интереснее, ибо размером больше (наверное за счет них)

Первая - RTTI

[snikulov@solarwind c_vs_cpp]$ gcc try_me.c -o try_c
[snikulov@solarwind c_vs_cpp]$ g++ try_me.cpp -fno-rtti -o try_cpp
[snikulov@solarwind c_vs_cpp]$ ls -la
total 32
drwxrwxr-x. 2 snikulov snikulov 4096 2009-06-08 23:38 .
drwxrwxr-x. 6 snikulov snikulov 4096 2009-06-08 22:41 ..
-rwxrwxr-x. 1 snikulov snikulov 4728 2009-06-08 23:38 try_c
-rwxrwxr-x. 1 snikulov snikulov 5047 2009-06-08 23:38 try_cpp
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.c
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.cpp

Никакго эффекта. Угу.

Переходим к другой фиче - исключения

[snikulov@solarwind c_vs_cpp]$ g++ try_me.cpp -fno-exceptions -o try_cpp
[snikulov@solarwind c_vs_cpp]$ ls -la
total 32
drwxrwxr-x. 2 snikulov snikulov 4096 2009-06-08 23:39 .
drwxrwxr-x. 6 snikulov snikulov 4096 2009-06-08 22:41 ..
-rwxrwxr-x. 1 snikulov snikulov 4728 2009-06-08 23:38 try_c
-rwxrwxr-x. 1 snikulov snikulov 4818 2009-06-08 23:39 try_cpp
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.c
-rw-rw-r--. 1 snikulov snikulov 55 2009-06-08 22:43 try_me.cpp
[snikulov@solarwind c_vs_cpp]$

Уже лучше
4728 vs. 4818

Что же там такое - смотрим (я взял опцию -d ибо по остальному большого различия не увидел... хотя я конечно лукавлю - сами посмотрите)

[snikulov@solarwind c_vs_cpp]$ readelf -d try_c

Dynamic section at offset 0x4ec contains 20 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8048274
-= skip =-
[snikulov@solarwind c_vs_cpp]$ readelf -d try_cpp

Dynamic section at offset 0x52c contains 23 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libstdc++.so.6]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x80482c0
-= skip =-
snikulov@solarwind c_vs_cpp]$

Ну... Вообще бардак

Полагаем и время выполнения из-за этого должно немного проседать.
Проверяем (используем не совсем точный метод расчета):

[snikulov@solarwind c_vs_cpp]$ time ./try_c

real 0m0.002s
user 0m0.000s
sys 0m0.001s
[snikulov@solarwind c_vs_cpp]$ time ./try_cpp

real 0m0.005s
user 0m0.001s
sys 0m0.002s
[snikulov@solarwind c_vs_cpp]$


Ну приблизительно. А почему? Ну, как нетрудно догадаться, видимо из-за библиотек?
Проверим

[snikulov@solarwind c_vs_cpp]$ strace ./try_c
execve("./try_c", ["./try_c"], [/* 53 vars */]) = 0
brk(0) = 0x98aa000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=137461, ...}) = 0
mmap2(NULL, 137461, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f6f000
close(3) = 0
open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\253\227\0004\0\0\0\304"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1803388, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f6e000
mmap2(0x964000, 1513768, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x964000
mprotect(0xacf000, 4096, PROT_NONE) = 0
mmap2(0xad0000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16b) = 0xad0000
mmap2(0xad3000, 10536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xad3000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f6d000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7f6d6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xad0000, 8192, PROT_READ) = 0
mprotect(0x960000, 4096, PROT_READ) = 0
munmap(0xb7f6f000, 137461) = 0
exit_group(0) = ?

C++ версия должна быть "пожирнее"

[snikulov@solarwind c_vs_cpp]$ strace ./try_cpp
execve("./try_cpp", ["./try_cpp"], [/* 53 vars */]) = 0
brk(0) = 0x9e42000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=137461, ...}) = 0
mmap2(NULL, 137461, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb8097000
close(3) = 0
open("/usr/lib/libstdc++.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\3523\0004\0\0\0\360"..., 512) = 512
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8096000
fstat64(3, {st_mode=S_IFREG|0755, st_size=950040, ...}) = 0
mmap2(0x2fa000, 977644, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x2fa000
mmap2(0x3dd000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xe2) = 0x3dd000
mmap2(0x3e3000, 23276, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3e3000
close(3) = 0
open("/lib/libm.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`$\256\0004\0\0\0<"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=206204, ...}) = 0 mmap2(0xadf000, 159872, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xadf000 mmap2(0xb05000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25) = 0xb05000 close(3) = 0 open("/lib/libgcc_s.so.1", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0@O&\0004\0\0\0P"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=172840, ...}) = 0 mmap2(0x263000, 174312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x263000 mmap2(0x28d000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x29) = 0x28d000 close(3) = 0 open("/lib/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\253\227\0004\0\0\0\304"..., 512) = 512 fstat64(3, {st_mode=S_IFREG|0755, st_size=1803388, ...}) = 0 mmap2(0x964000, 1513768, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x964000 mprotect(0xacf000, 4096, PROT_NONE) = 0 mmap2(0xad0000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16b) = 0xad0000 mmap2(0xad3000, 10536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xad3000 close(3) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8095000 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8094000 set_thread_area({entry_number:-1 -> 6, base_addr:0xb8095b20, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xad0000, 8192, PROT_READ) = 0
mprotect(0xb05000, 4096, PROT_READ) = 0
mprotect(0x3dd000, 16384, PROT_READ) = 0
mprotect(0x960000, 4096, PROT_READ) = 0
munmap(0xb8097000, 137461) = 0
exit_group(0) = ?
[snikulov@solarwind c_vs_cpp]$

Ну вообщем понятно...
Оптимизировать непросто. Тут всегда балансируешь на гранях. Когда-то приходит время выбирать. Или быстро и красиво запрограммировать (конструкторы, деструкторы, перегрузки, и т.д.), или уместить все это в железку, чтобы приемлемо работало.

Пошел искать опцию как отключить libm из зависимостей.
-Wl,-nostdlib не помогло.

P.S.
В рассылке по Embedded Linux Developers Kit мужик задал вопрос - а кто-нибудь перл собирал для ресурсо-ограниченного оборудования?
Видимо не очень ограничен, если спрашивает.