Шрифт:
Интервал:
Закладка:
Вы даже не можете себе представить, какие системные вызовы использует такая маленькая программка:
Листинг 22.2. Файл prog.с
#include <stdio.h>
int main() {
printf("Hellon");
return 0;
}
Откомпилируйте эту программу (gcc -o prog prog.c) и запустите strace:
$ strace prog
Вы увидите следующий вывод:
execve("./a.out", ["./а.out"], [/* 21 vars */]) = 0
uname((sys="Linux", node="localhost.localdomain", ...}) = 0
brk(0) = 0x80495b4
open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 7
fstat64(7, {st_mode=S_IFREG|0644, st_size=31578, ...}) = 0
old_mmap(NULL, 31578, PROT_READ, MAP_PRIVATE, 7, 0) = 0x40014000
close(7) = 0
open("/lib/i686/libc.so.6", O_RDONLY) =7
read(7, "177ELF111 3 3 1 `u1В4 "..., 1024) = 1024
fstat64(7, {st_mode=S_IFREG|0755, st_size=1401027, ...}) = 0
old_mmap(0x42000000, 1264928, PROT_READ|PROT_EXEC, MAP_PRIVATE, 7, 0) = 0x42000000
mprotect(0x4212c000, 36128, PROT_NONE) = 0
old_mmap(0x4212c000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 7, 0x12c000) = 0x4212c000
old_mmap(0x42131000, 15648, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x42131000
close(7) = 0
munmap(0x40014000, 31578) = 0
brk(0) = 0x80495b4
brk(0x80495e4) = 0x80495e4
brk(0x804a000) = 0x804a000
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000
write(1, "Hellon", 6) =6
munmap(0x40014000, 4096) = 0
_exit(0) = ?
Читать вызовы нужно так:
имя системного вызова = возвращаемое значение
В нашем случае мы вывели на консоль шесть символов, поэтому вызов write() возвратит значение 6.
В случае, если системный вызов завершился неудачно (обычно код ошибки -1), программа strace выводит не только код, но и описание ошибки:
open("/foo/bar", O_RDONLY) = -1 ENOENT (No such file or directory)
Стандартные константы выводятся в их символьном представлении:
open("file.dat", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3
Сигналы также выводятся в символьном представлении, например:
sigsuspend([] <unfinished ...>
--- SIGINT (Interrupt) ---
+++ killed by SIGINT +++
Структуры, точнее члены структур, заключаются в фигурные скобки и выводятся в формате имя_члена=значение, например:
lstat("/dev/null", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 3), ...}) =0
Символьные указатели печатаются как строки в С, то есть их значения заключены в двойные кавычки:
read(3, "root::0:0:System Administrator:/"..., 1024) = 422
22.5. Оптимизация программ. Профайлер gprof
Ваша программа работает медленно? Скорее всего, причина кроется в неэффективном, медленном алгоритме. Существуют программы, позволяющие определить время работы каждой функции вашей программы и всей программы в целом. Программы такого рода называются профайлерами. В вашем дистрибутиве может присутствовать один из профайлеров gprof, prof, profiler.
Сейчас мы рассмотрим программу gprof (The GNU Profiler), позволяющую определить время работы каждой функции. Основные ключи программы представлены в таблице 22.3.
Ключи командной строки gprof Таблица 22.3
Ключ Назначение -а He выводить информацию о статических функциях -b Не выводить описание каждого поля в итоговой таблице -с Включить эвристический анализ текстового сегмента объектного файла с целью создания статического графика вызовов -e имя_функции На выводить отчет о работе указанной функции и обо всех функциях, которые из нее вызываются -E имя функции Не обрабатывать указанную функцию и все функции, которые она вызывает -f имя_функции выводить информацию только об указанной функции и обо всех функциях, которые из нее вызываются -F имя_функции Обрабатывать только указанную функцию и все функции, которые из нее вызываются -k func1 func2 Не выводить информацию о вызове функции func2 из функции func1 -s Создание итогового файла gmon.sum -z Вывести функции с нулевым процессорным временем22.5.1. Использование профайлера
Для использования профайлера нужно скомпилировать программу с опцией компилятора -pg и без опции -о. так как профайлер по умолчанию работает с файлом a.out. После этого запустите файл a.out, чтобы он создал файл gmon.out. Теперь запустите профайлер с параметром --nograph:
$ gcc -pg 1.с
$ ./а.out
$ gprof -b –no-graph
Без ключа -b профайлер выведет описание полей итоговой таблицы:
♦ Time: время работы функции в процентном соотношении;
♦ cumulative seconds: сумма числа секунд этой функции и вызывающих ее функций;
♦ self seconds: число секунд, потраченное на работу этой функции в отдельности;
♦ Calls: число вызовов;
♦ self ms/calls: количество миллисекунд, на протяжении которых функция выполнялась;
♦ total ms/calls: количество секунд, на протяжении которых выполнялась функция и все функции, которые вызываются данной функцией;
♦ name: имя функции.
Рис. 22.5. Программа gprof
Чтобы было понятно, что означает каждое поле, рассмотрим листинг 22.3.
Листинг 22.3. Демонстрационная программа
#include <stdio.h>
int function2() {
int i;
/* генерируем задержку */
for (i=0;i<9999999;i++) ;
return 777;
}
double function(void) {
int i;
double x = 7.2323232323, y=324343.3434;
/* генерируем задержку */
for (i=0;i<9999999;i++) x/y;
function2();
return x/y;
}
int main() {
int i;
double l;
for (i=0;i<10;i++) {
printf("%db",i);
l=function();
}
return 0;
}
Как видно из листинга, функция function() вызывается 10 раз (см. поле calls). В свою очередь, она вызывает функцию function2(), следовательно, число вызовов этой функции тоже равно 10. Функция function() выполняется 1.09 секунд (self seconds), а так как ее никто не вызывает (кроме main), то поле cumulative seconds также равно 1.09. Функция function2() работает 1.07 секунд, но ее вызывает функция function(), которая работает 1.09 секунд. Следовательно, поле cumulative seconds для второй функции равно 1,09+1.07=2.16. Поле self ms/call эквивалентно полю self seconds, только его величина представлена в миллисекундах. Поле total ms/call обратно полю cumulative call и содержит время выполнения этой функции и всех дочерних функций, в то время как поле cumulative call содержит время этой функции и всех родительских.
22.5.2. Как оптимизировать программу
В качестве оптимизации программы могу вам порекомендовать предпринять следующие действия:
1. Запустите профайлер, и пусть он определит время работы всех функций.
2. Перепишите функцию (или функции), которые занимают больше всего процессорного времени. Возможно, вам придется изменить алгоритм работы этих функций.
3. Когда алгоритм изменить невозможно, можно попытаться переписать часть кода функции на языке ассемблера, если, конечно, это не противоречит идеологии вашей программы (возможно, вы хотите, чтобы она запускалась на как можно большем количестве разных платформ — тут без С не обойтись). Если переработка функции невозможна или помогла мало, то попробуйте оптимизировать программу с помощью опций компилятора. Прежде всего выключите отладочную информацию (не указывайте опцию —g) — и размер программы станет меньше. Используйте одну из опций оптимизации -O.
Глава 23
Разработка графического приложения: библиотека GTK+
Сейчас мы поговорим о создании графического интерфейса для вашей Linux-программы. Как вы знаете, средствами одного С нормальный GUI не построишь, тем более что привычный пользователь Windows очень требователен не просто к наличию GUI, но и к дизайну формы (окна программы). Поэтому без дополнительных библиотек вам не обойтись. Самыми распространенными библиотеками для создания GUI являются библиотеки GTK+ и Qt. Рекомендуется использовать только эти библиотеки, поскольку велика вероятность того, что они уже будут установлены у пользователя (уж GNOME и KDE есть почти у всех). Рассмотрим подробно библиотеку GTK+, поскольку она, на мой взгляд, проще, чем Qt.
- Операционная система UNIX - Андрей Робачевский - Программное обеспечение
- Разработка приложений в среде Linux. Второе издание - Майкл Джонсон - Программное обеспечение
- Искусство программирования для Unix - Эрик Реймонд - Программное обеспечение
- Linux - Алексей Стахнов - Программное обеспечение
- Fedora 8 Руководство пользователя - Денис Колисниченко - Программное обеспечение
- Недокументированные и малоизвестные возможности Windows XP - Роман Клименко - Программное обеспечение
- Изучаем Windows Vista. Начали! - Дмитрий Донцов - Программное обеспечение
- Windows Vista - Виталий Леонтьев - Программное обеспечение
- Архитектура операционной системы UNIX - Морис Бах - Программное обеспечение
- Windows Vista. Трюки и эффекты - Юрий Зозуля - Программное обеспечение