момента; в чем полностью соответствует системному вызову time. Однако плюс к тому
поле tv_usec содержит число миллионных долей текущей секунды (значение этого поля
всегда меньше 1000000).
6.2.11. К данному параграфу вернитесь, изучив раздел про fork() и exit(). Каждый
процесс может пребывать в двух фазах: системной (внутри тела системного вызова - его
выполняет для нас ядро операционной системы) и пользовательской (внутри кода самой
программы). Время, затраченное процессом в каждой фазе, может быть измеряно системным
вызовом times(). Кроме того, этот вызов позволяет узнать суммарное время, затраченное
порожденными процессами (порожденными при помощи fork). Системный вызов заполняет
структуру
А. Богатырев, 1992-95 - 203 - Си в UNIX
struct tms {
clock_t tms_utime;
clock_t tms_stime;
clock_t tms_cutime;
clock_t tms_cstime;
};
и возвращает значение
#include
struct tms time_buf;
clock_t real_time = times(&time_buf);
Все времена измеряются в "тиках" - некоторых долях секунды. Число тиков в секунде
можно узнать таким системным вызовом (в системе Solaris):
#include
clock_t HZ = sysconf(_SC_CLK_TCK);
В старых системах, где таймер работал от сети переменного тока, это число получалось
равным 60 (60 Герц - частота сети переменного тока). В современных системах это 100.
Поля структуры содержат:
tms_utime
время, затраченное вызывающим процессом в пользовательской фазе.
tms_stime
время, затраченное вызывающим процессом в системной фазе.
tms_cutime
время, затраченное порожденными процессами в пользовательской фазе: оно равно
сумме всех tms_utime и tms_cutime порожденных процессов (рекурсивное суммирова-
ние).
tms_cstime
время, затраченное порожденными процессами в системной фазе: оно равно сумме
всех tms_stime и tms_cstime порожденных процессов (рекурсивное суммирование).
real_time
время, соответствующее астрономическому времени системы. Имеет смысл мерять
только их разность.
Вот пример программы:
#include
#include /* _SC_CLK_TCK */
#include /* SIGALRM */
#include /* не используется */
#include /* struct tms */
struct tms tms_stop, tms_start;
clock_t real_stop, real_start;
clock_t HZ; /* число ticks в секунде */
А. Богатырев, 1992-95 - 204 - Си в UNIX
/* Засечь время момента старта процесса */
void hello(void){
real_start = times(&tms_start);
}
/* Засечь время окончания процесса */
void bye(int n){
real_stop = times(&tms_stop);
#ifdef CRONO
/* Разность времен */
tms_stop.tms_utime -= tms_start.tms_utime;
tms_stop.tms_stime -= tms_start.tms_stime;
#endif
/* Распечатать времена */
printf("User time = %g seconds [%lu ticks]\n",
tms_stop.tms_utime / (double)HZ, tms_stop.tms_utime);
printf("System time = %g seconds [%lu ticks]\n",
tms_stop.tms_stime / (double)HZ, tms_stop.tms_stime);
printf("Children user time = %g seconds [%lu ticks]\n",
tms_stop.tms_cutime / (double)HZ, tms_stop.tms_cutime);
printf("Children system time = %g seconds [%lu ticks]\n",
tms_stop.tms_cstime / (double)HZ, tms_stop.tms_cstime);
printf("Real time = %g seconds [%lu ticks]\n",
(real_stop - real_start) / (double)HZ, real_stop - real_start);
exit(n);
}
/* По сигналу SIGALRM - завершить процесс */
void onalarm(int nsig){
printf("Выход #%d ================\n", getpid());
bye(0);
}
/* Порожденный процесс */
void dochild(int n){
hello();
printf("Старт #%d ================\n", getpid());
signal(SIGALRM, onalarm);
/* Заказать сигнал SIGALRM через 1 + n*3 секунд */
alarm(1 + n*3);
for(;;){} /* зациклиться в user mode */
}
А. Богатырев, 1992-95 - 205 - Си в UNIX
#define NCHLD 4
int main(int ac, char *av[]){
int i;
/* Узнать число тиков в секунде */
HZ = sysconf(_SC_CLK_TCK);
setbuf(stdout, NULL);
hello();
for(i=0; i < NCHLD; i++)
if(fork() == 0)
dochild(i);
while(wait(NULL) > 0);
printf("Выход MAIN =================\n");
bye(0);
return 0;
}
и ее выдача:
Старт #3883 ================
Старт #3884 ================
Старт #3885 ================
Старт #3886 ================
Выход #3883 ================
User time = 0.72 seconds [72 ticks]
System time = 0.01 seconds [1 ticks]
Children user time = 0 seconds [0 ticks]
Children system time = 0 seconds [0 ticks]
Real time = 1.01 seconds [101 ticks]
Выход #3884 ================
User time = 1.88 seconds [188 ticks]
System time = 0.01 seconds [1 ticks]
Children user time = 0 seconds [0 ticks]
Children system time = 0 seconds [0 ticks]
Real time = 4.09 seconds [409 ticks]
Выход #3885 ================
User time = 4.41 seconds [441 ticks]
System time = 0.01 seconds [1 ticks]
Children user time = 0 seconds [0 ticks]
Children system time = 0 seconds [0 ticks]
Real time = 7.01 seconds [701 ticks]
Выход #3886 ================
User time = 8.9 seconds [890 ticks]
System time = 0 seconds [0 ticks]
Children user time = 0 seconds [0 ticks]
Children system time = 0 seconds [0 ticks]
Real time = 10.01 seconds [1001 ticks]
Выход MAIN =================
User time = 0.01 seconds [1 ticks]
System time = 0.04 seconds [4 ticks]
Children user time = 15.91 seconds [1591 ticks]
Children system time = 0.03 seconds [3 ticks]
Real time = 10.41 seconds [1041 ticks]
Обратите внимание, что 72+188+441+890=1591 (поле tms_cutime для main).
6.2.12. Еще одна программа: хронометрирование выполнения другой программы. Пример:
timer ls -l
А. Богатырев, 1992-95 - 206 - Си в UNIX
/* Хронометрирование выполнения программы */
#include
#include
#include
extern errno;
typedef struct _timeStamp {
clock_t real_time;
clock_t cpu_time;
clock_t child_time;
clock_t child_sys, child_user;
} TimeStamp;
TimeStamp TIME(){
struct tms tms;
TimeStamp st;
st.real_time = times(&tms);
st.cpu_time = tms.tms_utime +
tms.tms_stime +
tms.tms_cutime +
tms.tms_cstime;
st.child_time = tms.tms_cutime +
tms.tms_cstime;
st.child_sys = tms.tms_cstime;
st.child_user = tms.tms_cutime;
return st;
}
void PRTIME(TimeStamp start, TimeStamp stop){
clock_t HZ = sysconf(_SC_CLK_TCK);
clock_t real_time = stop.real_time - start.real_time;
clock_t cpu_time = stop.cpu_time - start.cpu_time;
clock_t child_time = stop.child_time - start.child_time;
printf("%g real, %g cpu, %g child (%g user, %g sys), %ld%%\n",
real_time / (double)HZ,
cpu_time / (double)HZ,
child_time / (double)HZ,
stop.child_user / (double)HZ,
stop.child_sys / (double)HZ,
(child_time * 100L) / (real_time ? real_time : 1)
);
}
А. Богатырев, 1992-95 - 207 - Си в UNIX
TimeStamp start, stop;
int main(int ac, char *av[]){
char *prog = *av++;
if(*av == NULL){
fprintf(stderr, "Usage: %s command [args...]\n", prog);
return(1);
}
start = TIME();
if(fork() == 0){
execvp(av[0], av);
perror(av[0]);
exit(errno);
}
while(wait(NULL) > 0);
stop = TIME();
PRTIME(start, stop);
return(0);
}
6.3. Свободное место на диске.
6.3.1. Системный вызов ustat() позволяет узнать количество свободного места в файло-
вой системе, содержащей заданный файл (в примере ниже - текущий каталог):
#include
#include
#include
struct stat st; struct ustat ust;
void main(int ac, char *av[]){
char *file = (ac==1 ? "." : av[1]);
if( stat(file, &st) < 0) exit(1);
ustat(st.st_dev, &ust);
printf("На диске %*.*s\n"
"%ld свободных блоков (%ld Кб)\n"
"%d свободных I-узлов\n",
sizeof ust.f_fname, sizeof ust.f_fname,
ust.f_fname, /* название файловой системы (метка) */
ust.f_tfree, /* блоки по 512 байт */
(ust.f_tfree * 512L) / 1024,
ust.f_tinode );
}
Обратите внимание на запись длинной строки в printf: строки, перечисленные последова-
тельно, склеиваются ANSI C компилятором в одну длинную строку:
char s[] = "This is" " a line " "of words";
совпадает с
char s[] = "This is a line of words";
6.3.2. Более правильно, однако, пользоваться сисвызовом statvfs - статистика по вир-
туальной файловой системе. Рассмотрим его в следующем примере: копирование файла с
проверкой на наличие свободного места.
А. Богатырев, 1992-95 - 208 - Си в UNIX
#include
#include
#include
#include
#include /* O_RDONLY */
#include
#include
#include
#include /* MAXPATHLEN */
char *progname; /* имя программы */
void error(char *fmt, ...){
va_list args;
va_start(args, fmt);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
va_end(args);
}
int copyFile(char *to, char *from){ /* куда, откуда */
char newname[MAXPATHLEN+1];
char answer[20];
struct stat stf, stt;
int fdin, fdout;
int n, code = 0;
char iobuf[64 * 1024];
char *dirname = NULL, *s;
if((fdin = open(from, O_RDONLY)) < 0){
error("Cannot read %s", from);
return (-1);
}
fstat(fdin, &stf);
if((stf.st_mode & S_IFMT) == S_IFDIR){
close(fdin);
error("%s is a directory", from);
return (-2);
}
А. Богатырев, 1992-95 - 209 - Си в UNIX
if(stat(to, &stt) >= 0){
/* Файл уже существует */
if((stt.st_mode & S_IFMT) == S_IFDIR){
/* И это каталог */