From: Ben Pfaff Date: Wed, 15 Sep 2004 23:26:27 +0000 (+0000) Subject: Update docs. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=699944803572c46c550a39027c0ebd935b0d61bc;p=pintos-anon Update docs. --- diff --git a/doc/Makefile b/doc/Makefile index 8d86141..88c9e85 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,5 +1,5 @@ TEXIS = projects.texi intro.texi threads.texi mlfqs.texi userprog.texi \ -filesys.texi vm.texi standards.texi +filesys.texi vm.texi standards.texi doc.texi devel.texi debug.texi all: projects.html projects.info diff --git a/doc/debug.texi b/doc/debug.texi new file mode 100644 index 0000000..e9bb413 --- /dev/null +++ b/doc/debug.texi @@ -0,0 +1,179 @@ +@node Debugging Tools, , Project Documentation, Top +@appendix Debugging Tools + +Many tools lie at your disposal for debugging Pintos. This appendix +introduces you to a few of them. + +@menu +* printf:: +* ASSERT:: +* DEBUG:: +* Backtraces:: +* i386-elf-gdb:: +* Modifying Bochs:: +@end menu + +@node printf +@section @code{printf()} + +Don't underestimate the value of @code{printf()}. The way +@code{printf()} is implemented in Pintos, you can call it from +practically anywhere in the kernel, whether it's in a kernel thread or +an interrupt handler, almost regardless of what locks are held. + +@code{printf()} isn't useful just because it can print data members. +It can also help figure out when and where something goes wrong, even +when the kernel crashes or panics without a useful error message. The +strategy is to sprinkle calls to @code{print()} with different strings +(e.g.@: @code{"1\n"}, @code{"2\n"}, @dots{}) throughout the pieces of +code you suspect are failing. If you don't even see @code{1} printed, +then something bad happened before that point, if you see @code{1} +but not @code{2}, then something bad happened between those two +points, and so on. Based on what you learn, you can then insert more +@code{printf()} calls in the new, smaller region of code you suspect. +Eventually you can narrow the problem down to a single statement. + +@node ASSERT +@section @code{ASSERT} + +Assertions are useful because they can catch problems early, before +they'd otherwise be notices. Pintos provides a macro for assertions +named @code{ASSERT}, defined in @code{}, that you can use for +this purpose. Ideally, each function should begin with a set of +assertions that check its arguments for validity. (Initializers for +functions' local variables are evaluated before assertions are +checked, so be careful not to assume that an argument is valid in an +initializer.) You can also sprinkle assertions throughout the body of +functions in places where you suspect things are likely to go wrong. + +When an assertion proves untrue, the kernel panics. The panic message +should help you to find the problem. See the description of +backtraces below for more information. + +@node DEBUG +@section @code{DEBUG} + +The @code{DEBUG} macro, also defined in @code{}, is a sort of +conditional @code{printf()}. It takes as its arguments the name of a +``message class'' and a @code{printf()}-like format string and +arguments. The message class is used to filter the messages that are +actually displayed. You select the messages to display on the Pintos +command line using the @option{-d} option. This allows you to easily +turn different types of messages on and off while you debug, without +the need to recompile. + +For example, suppose you want to output thread debugging messages. To +use a class named @code{thread}, you could invoke @code{DEBUG} like +this: +@example +DEBUG(thread, "thread id: %d\n", id); +@end example +@noindent +and then to start Pintos with @code{thread} messages enable you'd use +a command line like this: +@example +pintos run -d thread +@end example + +@node Backtraces +@section Backtraces + +When the kernel panics, it prints a ``backtrace,'' that is, a summary +of how your program got where it is, as a list of addresses inside the +functions that were running at the time of the panic. You can also +insert a call to @code{debug_backtrace()}, prototyped in +@file{}, at any point in your code. + +The addresses in a backtrace are listed as raw hexadecimal numbers, +which are meaningless in themselves. You can translate them into +function names and source file line numbers using a tool called +@command{i386-elf-addr2line}.@footnote{If you're using an 80@var{x}86 +system for development, it's probably just called +@command{addr2line}.} + +The output format of @command{i386-elf-addr2line} is not ideal, so +we've supplied a wrapper for it simply called @command{backtrace}. +Give it the name of your @file{kernel.o} as the first argument and the +hexadecimal numbers composing the backtrace (including the @samp{0x} +prefixes) as the remaining arguments. It outputs the function name +and source file line numbers that correspond to each address. + +If the translated form of a backtrace is garbled, or doesn't make +sense (e.g.@: function A is listed above function B, but B doesn't +call A), then it's a good sign that you're corrupting a kernel +thread's stack, because the backtrace is extracted from the stack. +Alternatively, it could be that the @file{kernel.o} you passed to +@command{backtrace} does not correspond to the kernel that produced +the backtrace. + +@node i386-elf-gdb +@section @command{i386-elf-gdb} + +You can run the Pintos kernel under the supervision of the +@command{i386-elf-gdb} debugger.@footnote{If you're using an +80@var{x}86 system for development, it's probably just called +@command{addr2line}.} There are two steps in the process. First, +start Pintos with the @option{--gdb} option, e.g.@: @command{pintos +--gdb run}. Second, in a second terminal, invoke @command{gdb} on +@file{kernel.o}: +@example +i386-elf-gdb kernel.o +@end example +@noindent and issue the following @command{gdb} command: +@example +target remote localhost:1234 +@end example + +At this point, @command{gdb} is connected to Bochs over a local +network connection. You can now issue any normal @command{gdb} +commands. If you issue the @samp{c} command, the Bochs BIOS will take +control, load Pintos, and then Pintos will run in the usual way. You +can pause the process at any point with @key{Ctrl+C}. If you want +@command{gdb} to stop when Pintos starts running, set a breakpoint on +@code{main()} with the command @code{break main} before @samp{c}. + +You can read the @command{gdb} manual by typing @code{info gdb} at a +terminal command prompt, or you can view it in Emacs with the command +@kbd{C-h i}. Here's a few commonly useful @command{gdb} commands: + +@table @code +@item c +Continue execution until the next breakpoint or until @key{Ctrl+C} is +typed. + +@item break @var{function} +@itemx break @var{filename}:@var{linenum} +@itemx break *@var{address} +Sets a breakpoint at the given function, line number, or address. +(Use a @samp{0x} prefix to specify an address in hex.) + +@item p @var{expression} +Evaluates the given C expression and prints its value. +If the expression contains a function call, the function will actually +be executed, so be careful. + +@item l *@var{address} +Lists a few lines of code around the given address. +(Use a @samp{0x} prefix to specify an address in hex.) + +@item bt +Prints a stack backtrace similar to that output by the +@command{backtrace} program described above. + +@item p/a @var{address} +Prints the name of the function or variable that occupies the given +address. +(Use a @samp{0x} prefix to specify an address in hex.) +@end table + +If you notice unexplainable behavior while using @command{gdb}, there +are three possibilities. The first is that there is a bug in your +modified Pintos. The second is that there is a bug in Bochs's +interface to @command{gdb} or in @command{gdb} itself. The third is +that there is a bug in the original Pintos code. The first and second +are quite likely, and you should seriously consider both. We hope +that the third is less likely, but it is also possible. + +@node Modifying Bochs +@section Modifying Bochs + diff --git a/doc/devel.texi b/doc/devel.texi new file mode 100644 index 0000000..3491a36 --- /dev/null +++ b/doc/devel.texi @@ -0,0 +1,3 @@ +@node Development Tools +@appendix Development Tools + diff --git a/doc/doc.texi b/doc/doc.texi new file mode 100644 index 0000000..55a80f5 --- /dev/null +++ b/doc/doc.texi @@ -0,0 +1,128 @@ +@node Project Documentation, Debugging Tools, Coding Standards, Top +@appendix Project Documentation + +When you submit your projects, you will be expected to also turn in +three files documenting them: @file{README}, @file{DESIGNDOC} and +@file{TESTCASE}. These guidelines explain what we want to see in +those files. + +Your submission should have exactly one of each file, in the +appropriate directory (e.g.@: for Assignment 1, place the files in the +@file{threads} directory). These files must be written in plain text +format (not Microsoft Word, not PDF). We recommend a text width of 65 +characters per line, with a hard limit of 80. + +@menu +* README:: +* DESIGNDOC :: +* TESTCASE :: +@end menu + +@node README +@section @file{README} + +This is the easiest of the bunch. It's the document we'll read while +trying to get your assignment to run. First, place all of your names +and Leland IDs (usernames) at the top. Next, you should also explain +any quirks with your program, such as known show-stopper bugs, weird +dependencies, and so on. + +If you added extra credit features to your project, explain them +concisely in the @file{README}. Otherwise, we're likely to miss them. + +@node DESIGNDOC +@section @file{DESIGNDOC} + +This file is our primary tool for assessing your design. Therefore, +you should be certain to explain your design in some decent amount of +detail. As a broad rule of thumb, we should be able to explain what +basic data structures and algorithms you used to solve the problem +after reading the @file{DESIGNDOC}, but without looking at the code. + +The easiest way to present your @file{DESIGNDOC} is to break it down +by parts of the project (e.g.@: for project 1, you can break the +@file{DESIGNDOC} into four parts). For each part, you should describe +the functionality that needs to be added, the data structures and +algorithms used to solve that problem from a high level, and the +motivations for each decision/change you make to the code. Your +@file{DESIGNDOC} needs to explain and justify your design. That is, +we should be able to understand what you did, and why you chose to do +it that way. The ``why'' should be in concrete terms of greater speed, +better space efficiency, cleaner code, or some other real measure of +goodness. + +Things you @emph{don't} need: an explanation of the pre-existing +Pintos code, an explanation of the project spec, justification for the +project (e.g.@: we don't need you to explain to us why filesystems are +important to an operating system), a play-by-play of every change you +made to the system, any other pontificating. (You may laugh at some +of the things listed above, but we've gotten all of them in the past.) +The @file{DESIGNDOC} needs to discuss design decisions and trade-offs +and the rationales behind them. Any other things can be left out, to +save your time and ours. + +Finally, please keep your @file{DESIGNDOC} as short as you can, +without sacrificing key design decisions. You should be brief, yet +complete. We don't want to read novels. + +@node TESTCASE +@section @file{TESTCASE} + +The @file{TESTCASE} file should contain all the information about how +you tested your programs. At minimum, this file should contain the +output from all the tests that we've provided, with any explanations +needed to reproduce the output (arguments to the program, turning +features on the program on or off, and so on). + +Additionally, you should detail all tests you write yourself. You are +expected to write tests for features which our tests don't cover, and +to write some additional stress tests, since our tests will not +necessarily be too strenuous. If you feel that such tests are not +required, you should explain why you feel so. For each test that you +write, explain how we can use them, and show some sample output from a +run. + +Specifically, here are some pointers for writing @file{TESTCASE} files +which will make them more succinct and us more likely to understand the +tests you write: + +@itemize @bullet +@item +Show us that you tested each part of your assignment. + +@item +Clearly state in your @file{TESTCASE} file what each test is supposed +to test. You should be testing not only the common case, but testing +corner cases. Specify what criteria or issue is being tested. For +example, in testing @code{thread_join()} you would have specified that +you test @code{thread_join()} when it is called multiple times on the +same child thread. + +@item +Make your tests as succinct as possible. Most students in the past +have done a great job with the testing of @code{thread_join()}, +creating very succinct short tests. We like that. + +@item +Your test cases should be placed in a subdirectory called +@file{testcases} within the project directory. So for project 1, they +should be in @file{pintos/src/threads/testcases}. + +@item +Think about what may actually crash your code. +@end itemize + +Your @file{TESTCASE} file is also where you can show us the +improvements that your code makes to the performance of the system. +You should be able to show us ``before'' and ``after'' performance +data, and explain how the data shows the improvement. For example, +for Problem 1-4, you should show us in the @file{TESTCASE} printouts +from a workload for the non-Solaris scheduler and the Solaris +scheduler and explain why the Solaris scheduler is better. + +Finally, we cannot stress enough the importance of being brief and +complete. + +Keep in mind that the quality of your testing is worth 10% of your +project grade. The bulk of this will be determined from the +@file{TESTCASE} file. diff --git a/doc/intro.texi b/doc/intro.texi index 82e4504..9f86704 100644 --- a/doc/intro.texi +++ b/doc/intro.texi @@ -224,12 +224,11 @@ The @command{pintos} program offers multiple options for running Pintos. Use @code{pintos help} to see a list of the options. You can select a simulator other than Bochs, although the Leland systems only have Bochs installed. You can start the simulator running a debugger -(@pxref{Debugging Pintos}). You can set the amount of memory to give -the VM. Finally, you can set up how you want VM output to be -displayed: use @option{-nv} to turn off the VGA display, @option{-t} -to use your terminal window as the VGA display instead of opening a -new window, or @option{-ns} to suppress the serial output to -@code{stdout}. +(@pxref{i386-elf-gdb}). You can set the amount of memory to give the +VM. Finally, you can set up how you want VM output to be displayed: +use @option{-nv} to turn off the VGA display, @option{-t} to use your +terminal window as the VGA display instead of opening a new window, or +@option{-ns} to suppress the serial output to @code{stdout}. The @command{pintos} program offers commands other than @samp{run} and @samp{help}, but we won't have any need for them until project 2. diff --git a/doc/projects.texi b/doc/projects.texi index a342fe7..90b85e9 100644 --- a/doc/projects.texi +++ b/doc/projects.texi @@ -9,6 +9,8 @@ * Project 4--File Systems:: * Multilevel Feedback Scheduling:: * Coding Standards:: +* Project Documentation:: +* Debugging Tools:: @end menu @include intro.texi @@ -16,7 +18,7 @@ @include userprog.texi @include vm.texi @include filesys.texi -@c @include devel.texi @include mlfqs.texi @include standards.texi @include doc.texi +@include debug.texi diff --git a/doc/standards.texi b/doc/standards.texi index 28bfc81..4b3bbef 100644 --- a/doc/standards.texi +++ b/doc/standards.texi @@ -1,4 +1,4 @@ -@node Coding Standards, , Multilevel Feedback Scheduling, Top +@node Coding Standards, Project Documentation, Multilevel Feedback Scheduling, Top @appendix Coding Standards All of you should have taken a class like CS 107, so we expect you to @@ -21,6 +21,8 @@ our coding standards will affect our grading. @menu * Coding Style:: * Conditional Compilation:: +* C99:: +* Unsafe String Functions:: @end menu @node Coding Style diff --git a/doc/threads.texi b/doc/threads.texi index c1fcfff..7f9c975 100644 --- a/doc/threads.texi +++ b/doc/threads.texi @@ -20,7 +20,6 @@ side. Compilation should be done in the @file{threads} directory. * Problem 1-3 Priority Scheduling:: * Problem 1-4 Advanced Scheduler:: * Threads FAQ:: -* Multilevel Feedback Scheduling:: @end menu @node Understanding Threads @@ -30,13 +29,16 @@ The first step is to read and understand the initial thread system. Pintos, by default, implements thread creation and thread completion, a simple scheduler to switch between threads, and synchronization primitives (semaphores, locks, and condition variables). -@c FIXME: base system doesn't do anything. Debugger sucks. -However, there's a lot of magic going on in some of this code, so you -should compile and run the base system to see a simple test of the -code. You should read through the source code by hand to see what's -going on. If you like, you can add calls to @code{printf()} almost + +However, there's a lot of magic going on in some of this code, so if +you haven't already compiled and run the base system, as described in +the introduction (@pxref{Introduction}), you should do so now. You +can read through parts of the source code by hand to see what's going +on. If you like, you can add calls to @code{printf()} almost anywhere, then recompile and run to see what happens and in what -order. +order. You can also run the kernel in a debugger and set breakpoints +at interesting spots, single-step through code and examine data, and +so on. @xref{i386-elf-gdb}, for more information. When a thread is created, you are creating a new context to be scheduled. You provide a function to be run in this context as an @@ -59,16 +61,19 @@ been provided for you in @file{threads/switch.S} (this is 80@var{x}86 assembly; don't worry about understanding it). It involves saving the state of the currently running thread and restoring the state of the thread we're switching to. -@c FIXME -Slowly trace through a context switch to see what happens. Be sure to -keep track of each thread's address and state, and what procedures are -on the call stack for each thread. You will notice that when one -thread calls @code{switch_threads()}, another thread starts running, -and the first thing the new thread does is to return from -@code{switch_threads()}. We realize this comment will seem cryptic to + +Using the @command{gdb} debugger, slowly trace through a context +switch to see what happens (@pxref{i386-elf-gdb}). You can set a +breakpoint on the @code{schedule()} function to start out, and then +single-step from there. Be sure to keep track of each thread's +address and state, and what procedures are on the call stack for each +thread. You will notice that when one thread calls +@code{switch_threads()}, another thread starts running, and the first +thing the new thread does is to return from +@code{switch_threads()}. We realize this comment will seem cryptic to you at this point, but you will understand threads once you understand why the @code{switch_threads()} that gets called is different from the -@code{switch_threads()} that returns. +@code{switch_threads()} that returns. @c FIXME @strong{Warning}: In Pintos, each thread is assigned a small, fixed-size execution stack just under @w{4 kB} in size. The kernel @@ -279,7 +284,7 @@ You may assume a static priority for this problem. It is not necessary to ``re-donate'' a thread's priority if it changes (although you are free to do so). -@node Threads FAQ, Multilevel Feedback Scheduling, Problem 1-4 Advanced Scheduler, Project 1--Threads +@node Threads FAQ @section FAQ @enumerate 1