3

UPDATE

I had very long lines in the file, and I put a newline after each 80th character (I used the sed command for that). Now the programs work fine. I can time them, and the results make sense.

Though, I have no idea why that caused a problem.

TLDR;

Using the /usr/bin/time command on my C programs does not work as expected. The time command ends before the C program, sometimes without output. E.g.

/usr/bin/time ./cat_8 lorem_ipsum.txt

Problem description

I am doing the exercise 8.1 of K&R of chapter 8.

Exercise 8-1. Rewrite the program cat from Chapter 7 using read, write, open and close instead of their standard library equivalents. Perform experiments to determine the relative speeds of the two versions.

Excerpt From: Brian W. Kernighan. The C Programming Language, Second Edition

You can see the programs below. The problem I have is with both programs.

I try to time the programs to compare them. The file size lorem_ipsum.txt is 35M.

me@virtualbox:~$ ls -hs lorem_ipsum.txt
35M lorem_ipsum.txt

The cat programs run without issue, but I cannot get a result from the time command for some reason. Google cannot help and I am clueless.

I compiled the programs with gcc, no options except the -o of course. I work on an Ubuntu virtual machine.

Does anyone know what the problem might be or what I am doing wrong?

Chapter 8 (cat_8 program)

#include <fcntl.h>
#include <syscall.h>
#include <stdio.h>

void error(char *fmt, ...);

/* cat: concatenate file */
int main(int argc, char** argv) {

    int fd;
    void filecopy(int, int);
    char *prog = argv[0]; /* program name for errors */

    if (argc == 1)
        filecopy(0, 1);
    else
        while (--argc > 0)
            if ((fd = open(*++argv, O_RDONLY, 0)) == -1)
                error("%s: can't open %s\n", prog, *argv);
            else {
                filecopy(fd, 1);
                close(fd);
            }

    return 0;
}

/* filecopy: copy file ifp to file ofp */
void filecopy(int fdin, int fdout) {
    char buf[BUFSIZ];
    int n;

    while ((n = read(fdin, buf, BUFSIZ)) > 0)
        write(fdout, buf, n);

}

Chapter 7 (cat_7 program)

#include <stdio.h>
#include <stdlib.h>

/* cat: concatenate file, version 2 */
int main(int argc, char* argv[]) {

    FILE *fp;
    void filecopy(FILE *, FILE *);
    char *prog = argv[0]; /* program name for errors */

    if (argc == 1)
        filecopy(stdin, stdout);
    else
        while (--argc > 0)
            if ((fp = fopen(*++argv, "r")) == NULL) {
                fprintf(stderr, "%s: can't open %s\n", prog, *argv);
                exit(1);
            } else {
                filecopy(fp, stdout);
                fclose(fp);
            }

    if (ferror(stdout)) {
        fprintf(stderr, "%s: error writing stdout\n", prog);
        exit(2);
    }

    return 0;
}

/* filecopy: copy file ifp to file ofp */
void filecopy(FILE *ifp, FILE *ofp) {
    int c;

    while ((c = getc(ifp)) != EOF)
        putc(c, ofp);

}
  • 1
    sometimes? What does strace show time sometimes doing? E.g. strace -f -o trace time ... – thrig May 15 '17 at 18:30
  • strace has the same issue. sometimes means that I can see the output somewhere in the middle of the text that is displayed on the screen. It's just so much text that I cannot scroll all the way up to the command in the shell. It could be that the output is somewhere before the visible shell; in other words the time command and the C program might be running concurrently. Not sure though. – Ely May 15 '17 at 18:54
  • cat_7 is calling close on a FILE* which is wrong; your compiler should have complained unless it is using the 27-year-old C standard (and IMO even then it should warn). This is likely to lose some of the output, but on no reasonable system should it lose 35M. – dave_thompson_085 May 16 '17 at 6:36
  • Thanks @dave_thompson_085 for the bug. I corrected it. When I have time I'll try sourcejedi's suggestion on the machine linked. It must be my file because everybody says program looks ok. But I don't see what is wrong. I can open my file with vim and gedit; it looks ok to me. I don't know where to search.... – Ely May 16 '17 at 6:45
3

Does anyone know what the problem might be or what I am doing wrong?

I don't believe it's anything wrong in your two solutions. There's simply no way these could request the behaviour you describe... without deliberately forking a second process (and you don't call fork()), or killing the time process, or hacking the kernel etc.

Perhaps your computer is broken.

Previously I've had weird behaviour caused by silent disk corruption. I might try running debsums or rpm --verify -a to check.

It could equally be a bug in the chain of software which displays the output.

For example gnome-terminal 3.22 has a crash bug when fed some sequence of binary. Several versions of the Linux kernel had this great bug where sending more than 4kB over a terminal emulator ("pseudo-tty") to a read-line enabled program such as a shell, could lose some lines. Dumping 35MB of text at a time is relatively unusual, there could be some bug like that in your OS.

If you can reproduce the problem with an input file of a mere 100kB, here's a different computer for you which is almost certainly not corrupted in the same way as the host computer it is run on. Console output is pretty slow, there's only a few megabytes of free space as well. The output from running your program under time will not match real seconds for some reason, it shouldn't matter for this question though. The clipboard text box doesn't accept keyboard input for me (Firefox 53), so I used the right-click menu to copy data in through /dev/clipboard as per the FAQ.

0

Looks like the program work.

Does your time command work right?

Try:

leisner@y50 ~ $ /usr/bin/time sleep 10s                                                                                                                 
0.00user 0.00system 0:10.00elapsed 0%CPU (0avgtext+0avgdata 1728maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps

Also are you mixing the output into the time result -- try something like:

time cat myfile.txt >/dev/null

It shouldn't -- but running in a VM causes an extra layer of buffering.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.