Computer Systems: A Programmer’s Perspective (CSAPP) is the second book recommended in my favorite online computer science curriculum – teachyourselfcs. It’s meant to teach you how computers work from a low-level perspective. As its name suggests, it’s geared towards programmers. It introduces computer architecture concepts only to the extent of them helping you become a better programmer. Once the lower-level concepts are introduced, it builds on that knowledge to understand how the hardware interacts with the operating system through the kernel. At the very end, it even tackles concepts of networking and concurrent programming.
Overview
The book is divided into three parts. It starts with low-level concepts of the hardware, in particular the processor, and how it executes programs. Then it moves on to the interaction between the operating system and the hardware while executing programs. Finally, it studies programs interacting between them, for example in networking and concurrent programming.
The book is very technical and does not spare lower-level details where they are needed. However, it does try to focus hardware and systems concepts on those that are helpful to become a better programmer.
Besides the quality of the text, the exercises are well designed and very rewarding. Some of the most challenging ones involve the creation of basic, but functional, versions of useful programs like a shell and a concurrent web server.
While the principles introduced in CSAPP aren’t limited to them, all of the concepts and exercises revolve around C and Linux. If you’re not already familiar with C or a similar programming language, the authors suggest reading Kernighan and Ritchie’s classic book.
Part I: Program Structure and Execution
In this part of the book, we are taught how the CPU “reads” programs. How everything, at the lowest level, is just bits, with no difference between “data” and “instructions” and the context determining how bits are interpreted.
Since programs are just bits, we first study how data is represented with them. In particular, there is an in-depth study of numerical data representation. Starting with integer values, encoding schemes like Two’s- and One’s- complement are introduced. For real numbers, floating-point representation is studied. This level of detail is very useful to understand some programming bugs like integer overflow, floating-point precision limits, and so on. System portability can also be better understood with aspects such as byte-ordering (endianness).
Following this study of bit-level representation, the lowest level of code abstraction, beyond pure bits, is introduced – assembly code. This helps to understand programs as, in essence, a series of very basic instructions that the processor can execute. We see how the processor has a small set of data stores, the registers, to “remember” some intermediate results. The stack discipline, which facilitates function calls and recursion, is also introduced.
After the essentials of assembly, CSAPP introduces the very design of an instruction set architecture (the set of instructions a processor can execute): the y86-64 – a simplified version of the x86-64 instruction set. This section is helpful to understand, at a finer level, how bits represent instructions and how the processor divides instructions into “parts” in order to pipeline them for better performance.
This part of the book concludes with a study of program optimization based on lower-level considerations which were introduced in the previous chapters.
Part II: Running programs on a system
The second part of the book goes up a few levels of abstraction and deals primarily with the interactions between programs and the operating system.
We start by studying in more detail the compilation of programs, particularly the linking phase. This will give insight into the way C handles different source files to create a single executable, how common libraries are shared between programs, and how assembly code is converted to an executable file.
Following this section, comes my favorite part of the book, exceptional control flow. Besides the different sorts of exceptions (interrupts, system calls, faults, and aborts) which involve both hardware and software to varying degrees, this chapter introduces processes and signals. This is a first step into concurrent programming and will teach you a lot about how the operating system manages processes.
Finally, virtual memory is introduced. The memory hierarchy is introduced in the first part of the book and offers a hardware-oriented understanding of it. In the virtual memory chapter, we turn to the interactions between hardware and software (via the OS kernel) to create the virtual memory – an abstraction of memory for processes.
Part III: Interaction and communication between programs
After studying both low-level hardware and software for a single program, the book turns its attention towards the interaction between programs, be it across different machines or not.
The first chapter introduces the Unix I/O interface along with the lower-level system calls included in it. Built upon them, it proposes a helpful “robust I/O” package (rio
) that will facilitate the development of programs in the next chapters. It’s particularly helpful to overcome some limitations of network I/O present in the Unix I/O.
Next, networking is introduced. It starts with an introduction of TCP/IP and how the Internet operates. Follows an introduction to sockets (used for I/O across networks) and the client-server model. Finally, a simple but quite functional web server is developped.
Finally, the book presents concurrent programming in more detail. It presents three ways of achieving concurrency: processes, I/O multiplexing, and threads. All of them are used to upgrade a simple server program of the networking chapter, which served requests sequentially, to handle client requests concurrently.
Conclusion
In my experience, this book was a tremendous wealth of knowledge. Each part of the book helped me understand better how computers work. Starting with how bits are used to represent data and programs. How processors execute instructions based on them. The way the operating system interacts with the hardware and manages running programs. Finally, how processes across the network interact with one another.
I thoroughly enjoyed studying this book. Particularly, for the better understanding I received of the way hardware, systems and programs interact. I highly recommend it to anyone interested in those subjects.
Additional resources
- Official website.
- Harvard’s CS 61.
- Repository with exercise solutions.
Detailed exercise solutions:
- Converting
int
tofloat
. - Converting
float
toint
. - Insthalling the y86-64 simulator.
- Basic shell with job control.