CS111 Scribe Notes for April 9, 2013By Matthew Lung
How to cope with complexity in OSA. Modularity: Breaking things into piecesWithout Modularity:
Looking at the word count program from Lecture 2 there is a problem: There are two copies of the read sector function. - a copy in the bootloader in MBR - a copy in word count itself To fix this, we can do one of three things:
Crypto Analysis-uses a lot of CPU I/O (0)___(1)___(2)___(3)___ CPU __(0)___(1)___(2)___(3) time------------------------> After I/O is done with (0) CPU can have (0)...This is inefficient, because I/O and CPU must wait for each other. Double Buffer-almost twice as fast I/O (0)(1)(2)(3)(4) CPU __(0)(1)(2)(3) time------------------------> After finishing with (0) the I/O buffers (1), while the CPU is running (0). This is ~twice as fast as not buffering. Note: triple buffering, quadra buffering,...etc will not further performance increase) There are trade-offs for this performance, in this case complexity is traded for performance increases. Internally the system buffers or reads ahead. ___________________________________________________________ Direct Memory Access (DMA) ![]() In regular memory accessing, the CPU tells the disk controller what it wants to be done, the disk controller then gets the necessary information and sends it back to the CPU. The CPU then moves that information to the RAM. This method is not very optimal, because the bus can obly be used for one thing at a time. Knowing this, the CPU uses the bus to request from the disk controller, the disk controller must return over the bus, and then the bus must be used to transfer the data to the RAM. Rather operating in this manner Direct Memory Access reduces the redundancy. In DMA the CPU sends commands to the disk controller, but these commands will direct the disk controller to send the data directly to the RAM. This process is shown in red and blue in the figure above. Brief Summary of Simple OS Modularity Problems
Looking at the read_sector function void read_sector(int S, int ptr_t a) can be changed to void read_sector(int S, int ptr_t a, int SectorSize) and int read(int S, int ptr_t buf, int bufsize) to size_t read(off_t offset, void* buf, size_t bufsize) Or More Generally: ssize_t read(void* buf, size_t bufsize) + off_t seek(off_t offset) But this is still assuming that there is only one file and only one device. How to tell whether modularity is good or bad.Look for:
Common Policy on Modularity: When there is no modularity there are many global variables and many functions used to fulfill small roles in operating the program. The plus side to this is that it runs fast the negative side is that it is often hard to understand and debug. ___________________________________________________________ Library Functions (What are their addresses?) in BIOS or in the Library Area ![]() Caller Code + Callee Code (lazy version): one function that calls itself int fact(int n) { if(n) return n*fact(n-1); else return 1; } Example: Non-optimized Factorial pushl %ebp movl $1, %eax <--Caller Beware! Callee can modify %eax movl %esp, %ebp <--We will preserve %ebp subl $8, %esp movl %ebx, -4(%ebp) movl 8(%ebp), %ebx tstl %ebx, %ebx jne .L5 .L1 movl -4(%ebp), %ebx movl %ebp, %esp popl %ebp ret <--The answer will be in %eax .L5 leal -1(%ebx), %eax movl %eax, (%esp) call fact imull %ebx, %eax jmp .L1 ![]() ___________________________________________________________ What can go wrong with function call modularity:
Function calls give soft modularity, but we want hard modularity which works even with buggy modules. To do this there are two common ways: 1. Client-Server: client code cannot step on the server memory and vice-versa. This works, but is very expensive. 2. Virtualization: the code run in virtualization can only stomp on itself; the OS insulates itself from the application. |