Assignment 3 FAQ, Errata, and Addenda

Due Friday, February 27, 2015 6:00 pm via sakai>
Due Friday, February 28, 2015 11:59 pm via sakai

Last update: Saturday, February 28, 2015 08:03 EST


Should the system be logging the number of system calls made only while tracing is on?
The process should be counting system calls all the time but printing them only after a call to trace(1) and not printing them initially or after a call to trace(0).
Should turning tracing off (using trace(0)) should be counted as a system call and added to the total count returned by trace(0)?
Yes, trace() is a system call so any call to trace will increment the process’ system call counter. Try adding some system calls between your traces and look at the difference between the trace() counts. For example:
	int a, b;
	char *hello = "hello, world\n";

	a = trace(0);
	b = trace(0);
	printf(1, "trace-trace: system calls executed = %d\n", b-a+1);
	a = trace(1);
	write(1, hello, strlen(hello));
	b = trace(0);
	printf(1, "trace-write-trace: system calls executed = %d\n", b-a+1);
Should produce:
trace-trace: system calls executed = 2
pid: 4 [try] syscall(16=write)
hello, world
pid: 4 [try] syscall(22=trace)
trace-write-trace: system calls executed = 3
When and what are we printing in the below example:
2.trace (1); //prints fork info from line 1 
3.fork();     // would this print fork information as a system call from trace?
4.trace(0);   //turn off trace
5.trace(1);    //would it print the fork info from the fork at line 3?
Please tell me what would print in the console for the above example.
When you call trace(1), you are simply trying on system call tracing from the current point. The is will print the lid, process name, system call name, and system call number for every system call after that (from that process). Trace will never print info about previous calls. And, yes, trace() counts as a system call just like any other one does.
If trace(0) is called in our try.c then we return the number of system calls made so far. if trace (1) do we also return the system calls made so far?
Yes. Trace return the same information (total # of system calls so far) no matter what the parameter is.
I get high system call counts when I do a printf.

printf is not a system call. It's a library function (you can look at the source) that parses the formatting string and calls the write system call. In many cases, printf will make many calls to write. Turn on system call tracing and you'll see a stream of writes (which will interfere with the ouput of printf.

For example, if you have code such as:

#include "types.h"
#include "user.h"
#include "fcntl.h"

main(int argc, char **argv)
	int a, b;
	char *hello = "hello, world\n";

	a = trace(0);
	write(1, hello, strlen(hello));
	b = trace(0);
	printf(1, "system calls executed = %d\n", b-a+1);
You’ll get output that looks like: hello, world system calls executed = 3
If you replace the write() call with
	printf(1, hello);

then you’ll get:

hello, world
system calls executed = 15
I am in a group of three, and our group was wondering if we could get extra credit for doing the optional part of the assignment.
Yes, you can get extra credit for the optional part.
Clarification question: we should add a system call trace, which would accept a 0 or 1 as an int argument
Correct. Trace will accept 0 or 1 as an argument. You don't need to check the value; you can use the C convention of 0 = "trace off" and non-0 = "trace on".
Clarification question: when we call trace(0) it simply returns number of system calls made so far and zeros-out our system call counter for a process
Not quite. You never reset the system call counter. trace(0) or trace(1) will always return the number of system calls that the process has made since it started to run.
Clarification question: when we call trace(1) we start our system call counter and print information for each system call during the execution of our test program. Our system call counter is being incremented until we get trace(0) system call. After we get trace(0) system call our counter becomes zero.
trace(1) will cause all subsequent system calls from this process following to be printed to the console. trace(0) turns the printing off. The per-process system call counter is never reset.
How do you run the try.c file?
try.c is just the C source for a regular program that you can compile and run under xv6. Compiling it should create an executable called try (which you run by typing the command try). You can create as many programs as you want to test various things. For every program (such as try.c), make sure that you create a target in the Makefile so that it gets compiled. Look at the Makefile and see how other user-level programs (e.g., echo, ls, kill, grep, etc.) are built and add a target for try.c (and/or whatever other programs you want to compile). All you’ll need to do is modify two targets: UPROGS and EXTRA.
How does the system know to associate that trace call with the system call "sys_trace". I can't seem to understand how you establish that link between the user function and the system call.
You should be able to figure this out by inspecting how other system calls work. For example, look at the getpid() system call, which returns the current process ID. Search for all occurrences of getpid in *.h *.S and *.c in the source and take a look at where getpid is used. For example, you’ll see syscall.h defines system call numbers. The magic of creating a user function that ends up doing the system call is implemented in usys.S, which defines SYSCALL. SYSCALL is a macro that defines a symbol for each system call name and, for each call, creates code that will move the system call number to the eax register and then execute a software interrupt (int instruction) to create the mode switch to the system call service routine. You’ll see a list of references to this macro in the file and will need to add one for trace().
Do we have any requirement for our test programs? As I understand we should submit our test programs along with other changes, right? Currently I have two tests in my test program and I am not sure if it will be enough for a good grade.

You should submit one or more test programs with your assignment and, in your document, explain what you’re testing. At a minimum, be sure to test:

  • trace on
  • trace off
  • total system call count returned on trace(0)
  • total system call count returned on trace(1)
  • a few function calls that clearly demonstrate testing works (e.g., write, getpid, etc.)

The key thing is to document what you’re testing and what output you got. I’ll be able to test your kernel with additional programs.

If I have three processes, A, B and C. A is running and B and C are ready. Then B preempts A. Who gets an increase in its context switch count? It should be B?


The xv6 scheduler() function is insanely simple. Processes are forced to give up the CPU on a clock tick - the kernel calls yield() on a timer interrupt in trap.c. yield() calls sched(), which calls swtch() to perform a context switch. The way xv6 works is that the scheduler is treated as a separate context. sched() calls switch() to save the current context (proc->context) and switch to the scheduler context (cpu->scheduler). This causes the scheduler to continue its for loop, where it finds a process to run and switches to it. The wasteful part is that if there’s only once process in the RUNNABLE state then the scheduler will switch back to that. You don’t have to worry about this happening. It’s still performing a context switch, even if a wasteful one, and you should count it.