CPS 356 Lecture notes: Demand Paging



Coverage: [OSCJ8] §§9.1-9.3 (pp. 393-405)


Overview

virtual = in effect, if not in essence

virtual memory: still limited by swaps


Virtual Memory

  • entire process need not be in memory before it can execute
  • major advantage: programs larger than main memory can run (Fig. 9.1)
  • frees programmers from memory limitations
  • allows processes to share files easily and implement shared memory (Fig. 9.3)
  • easy mechanism for process creation (copy-on-write)
  • motivation
    • declaration of 100x100 array when typically only a 10x10 portion of it is used
    • in cases where entire program is needed, it is generally not needed all at the same time
  • benefits:
    • programmers no longer constrained by amount of main memory
    • higher degree of multiprogramming → higher CPU utilization and throughput, with no increase in response time or turnaround time
    • less I/O required to load or swap programs into memory → each program runs faster
    • more pages required only if the heap or stack grow (Fig. 9.2)


Demand Paging

  • same idea as pure paging, but now you only load a page on demand
  • this gives a higher degree of multiprogramming with only a little more overhead
  • use a lazy swapper (now called a pager) (Fig. 9.4)
  • initial load (Fig. 9.5)
  • concept of a page fault
  • where can a page fault occur (instruction or operand)?
  • in pure paging, a page fault represents a fatal error
  • in demand paging, a page fault means an additional page must be brought into memory and the instruction re-started
  • why must the instruction be restarted?
  • pure demand paging: bring no page(s) in initially; every process will page fault at least once
  • concept of locality of reference
Performance of Demand Paging
  • effective access time
  • probability of a page fault p
  • (1-p)*ma + p*page fault time


Page fault time

  • 12 step process; see list on pp. 355-356
  • Fig. 9.6
  1. service the page-fault interrupt
  2. read in the page
  3. restart the process
    Which is the most time-expensive step?
      #2 is the most time-costly; typically 8 milliseconds
      AND waiting time in queue for device.
    ma = 200ns

    pft = 8ms

    (1-p)*(200) + p*8,000,000 = 200 + 7,999,800p

    effective access time is directly proportional to page-fault rate

    if p is 1/1000, effective access time is 8.2 microseconds, a slow-down by a factor of 40 (!!!!) because of demand paging

    if we want the slowdown to be less than 10%, we need p < 0.0000025

    that is, fewer than 1 out of 399,990 accesses should fault


Copy-on-Write

  • can we do better than pure demand paging?
  • recall fork()? seem wasteful? why?
  • copy-on-write: both processes (parent and child) share all pages initially, and a shared page is only copied if and when either process writes to a shared page
  • not all shared pages need to be set to copy-on-write (e.g., pages containing the executable code)
  • Figs. 9.7 & 9.8
  • currently Linux fork uses copy-on-write, but does copy the parent page table
  • vfork(): virtual memory fork():
    • parent is suspended
    • child uses address space and thread of control of the parent until a call to execve or exit.
    • does not use copy-on-write
    • does not even copy the page table of the parent process
    • vfork is intended to be used when the child calls exec immediately because no copying of pages takes place at all (i.e., it does not use copy-on-write)
    • extremely efficient method of process creation
    • sometimes used to implement command shells
    • vfork() is a special case of clone(2).  It is used to create  new  processes
      without  copying the page tables of the parent process.  It may be useful in
      performance-sensitive applications where a child is created which then imme-
      diately issues an execve(2).
      
  • Historic description
        Under Linux, fork(2) is implemented using copy-on-write pages, so  the  only
        penalty incurred by fork(2) is the time and memory required to duplicate the
        parent's page tables, and to create a unique task structure for  the  child.
        However,  in the bad old days a fork(2) would require making a complete copy
        of the caller's data space,  often  needlessly,  since  usually  immediately
        afterward  an exec(3) is done.  Thus, for greater efficiency, BSD introduced
        the vfork() system call, which did not fully copy the address space  of  the
        parent process, but borrowed the parent's memory and thread of control until
        a call to execve(2) or an exit occurred.  The parent process  was  suspended
        while the child was using its resources.  The use of vfork() was tricky: for
        example, not modifying data in the parent process depended on knowing  which
        variables were held in a register.
    


References

    [OSCJ8] A. Silberschatz, P.B. Galvin, and G. Gagne. Operating Systems Concepts with Java. John Wiley and Sons, Inc., Eighth edition, 2010.

Return Home