This exercise asks you to justify the multiprocess architecture by experiment, not by assertion. For each application below, you will state a hypothesis, design a measurement, run it, and report what the numbers show.

You are expected to use standard Unix tools to observe and document what happens. At minimum:

  • ps (and ps -eLf, ps -T, or ps axjf as appropriate) to observe process and thread structure;
  • /usr/bin/time -v to capture wall-clock time, user time, and system time;
  • top or htop to observe CPU utilization during a run;
  • strace or ltrace when you need to see what a process is actually doing;
  • gnuplot, matplotlib, or a spreadsheet to plot your results.

Include the exact commands you ran and their output in your report. “It was faster” is not evidence; a number is.

The applications:

Part 1: Echo Server (Isolation of Failure)

Hypothesis. If the server uses a process per client, then a crash or hang in one client’s handler does not affect other clients.

Experiment. Run the server. Connect two clients. Identify the child process handling one client (ps axjf or ps -eLf) and kill it (kill -9 <pid>). Then:

  1. Show that the other client’s connection is still alive.
  2. Show that a new client can still connect.

Evidence to include. The ps output showing the server’s child processes before and after the kill, the PID you killed, and a transcript of the surviving client.

Question to answer. What would happen in a thread-per-client server if one handler dereferenced a null pointer and crashed? Why?

Part 2: π Estimator (Parallelism and CPU Utilization)

Hypothesis. With N worker processes on an M-core machine, the wall-clock time to complete a fixed number of simulation samples decreases as N increases, up to N = M, and then flattens.

Experiment. Run the estimator with N = 1, 2, 4, 8, 16. For each N:

  1. Record wall-clock time and total CPU time (/usr/bin/time -v).
  2. Compute speedup relative to N = 1.
  3. Compute CPU utilization as (total CPU time) / (wall-clock time × M).
  4. Plot speedup versus N, and utilization versus N.

Before you run the experiment, determine M. M is the number of logical CPUs reported by the operating system. It is a factor in the result. If the machine has M logical CPUs and you run N worker processes with N > M, at most M of them can be executing at any instant. The remaining N − M processes are concurrent — they are in progress — but they cannot add to the degree of parallelism, which is capped by the hardware at M. The result is that speedup rises until N = M and then flattens. Use one of the following to find M:

nproc
lscpu | grep '^CPU(s):'
grep -c ^processor /proc/cpuinfo

Record M in your report, and note which command you used.

Report. A table of N, wall-clock time, speedup, and utilization, plus the two plots. A short paragraph explaining where the speedup flattens and why that value is related to M.

Question to answer. Amdahl’s Law predicts a limit even when N is large. Does your data show a limit? If so, estimate the serial portion S from your measured speedup at N = M, and compare it to what you would expect from the code. In your answer, be precise about what happens when N > M: the extra processes are still concurrent, but they do not add parallelism.

Optional (strongly encouraged). Run the same experiment with N > M, e.g., N = 2M and N = 4M. Show that the speedup does not increase past N = M. In your explanation, distinguish between two claims:

  • (a) The extra processes do not add parallelism — this is true for a CPU-bound workload like the π estimator.
  • (b) The extra processes do not help at all — this is workload- dependent. For an I/O-bound workload, concurrency past M can improve throughput even without additional parallelism, because waiting processes can be swapped out for runnable ones.

The π estimator is CPU-bound, so you should observe (a), not (b).

Part 3: Modern Web Browser (Process Isolation Under Failure)

Hypothesis. The browser’s process-per-tab architecture isolates failures: a crash in one tab does not affect other tabs or the browser itself.

Experiment. You will grow the browser’s process tree, then break it, and observe what survives.

Step 1: Observe the baseline.

  1. Close all browser windows and wait for the processes to exit.
  2. Launch the browser fresh, with no tabs loaded (or just a blank tab).
  3. Count the browser’s processes:
ps -o pid,ppid,rss,cmd -C chrome | tail -n +2 | wc -l
# or for Firefox:
ps -o pid,ppid,rss,cmd -C firefox | tail -n +2 | wc -l
  1. Record the count and the total RSS:
ps -o rss= -C chrome | awk '{s+=$1} END {print s}'

Portability note. ps -C <name> and --no-headers are GNU ps extensions. On macOS or BSD, use pgrep -fl "Google Chrome" instead, or use Activity Monitor (View → All Processes, Hierarchically) to observe the process tree.

Step 2: Grow the process tree.

  1. Open a new tab to about:blank. Count processes again.
  2. Open a new tab to a real page (e.g., https://www.sci.brooklyn.cuny.edu/cis). Count again.
  3. Repeat for three more tabs with different sites. Count after each.
  4. Plot process count versus number of tabs.

Step 3: Break one tab.

  1. Pick one tab whose renderer you can identify. Use the browser’s own task manager to get the PID, or find it via ps:
ps -o pid,ppid,cmd -C chrome | grep renderer
  1. Kill that renderer process:
kill -9 <pid>
  1. Observe immediately:
    • Does the tab show a “crashed” or “Aw, Snap!” page?
    • Do the other tabs still work? Reload them to confirm.
    • Does the browser’s main window still respond?
    • Did the process count drop by one, or by more?
  2. Record the process count after the kill.

Step 4: Compare browsers.

Repeat Steps 1–3 for at least one other browser (Firefox, Edge, or Safari). Note that:

  • Chrome and Edge share the Chromium code base, so their process models are similar.
  • Firefox uses its own multi-process architecture (historically called “Electrolysis” or e10s) and also isolates content processes from the browser process.
  • On macOS, Safari’s process model is visible in Activity Monitor under “View → All Processes, Hierarchically.”

Evidence to include.

  • A table: browser, number of tabs, process count, total RSS.
  • The ps output before and after the kill.
  • A screenshot or transcript of the crashed tab and a working neighboring tab.

Questions to answer.

  1. How many processes does the browser spawn for a single blank tab? What are they likely doing? (Hint: browser process, renderer, GPU, utility.)
  2. Does process count grow linearly with tabs? If not, why not? (Hint: the browser may reuse renderers for same-site tabs.)
  3. When you kill one renderer, what does the browser display? What happens to the other tabs? Relate this to the process-per-tab design.
  4. Would this experiment work on a single-process browser? Why or why not?

Optional Extensions

Same-site renderer sharing. Open two tabs to the same site and check whether they share a renderer process. Then open tabs to different sites and compare. This tests whether the browser isolates by tab or by site.

Isolation vs. protection. The crash experiment demonstrates isolation: a fault in one tab does not propagate to another. It does not demonstrate protection: that a malicious tab cannot read or write another tab’s memory. Both are consequences of the same process model — each tab runs in its own address space, enforced by hardware and the kernel — but only the isolation property is directly observable with the tools we have.

In one or two paragraphs, explain:

  1. Why does killing a renderer demonstrate isolation?
  2. Why does it not demonstrate protection? What experiment would you need to run to demonstrate protection, and why is it out of scope for this exercise?
  3. Which of the two properties would you rather have if you could only have one? Justify your answer in terms of the browser’s threat model (untrusted web pages, untrusted scripts, untrusted third-party content).

Deliverable

A concise presentation (12 minutes) covering, for each application:

  1. The architectural choice. What is being isolated, and from what? (Not a recap of the lecture — a one-sentence statement of the design.)
  2. The hypothesis. A falsifiable claim about what the architecture buys you.
  3. The measurement. What you measured, how, and on what hardware. For Part 2, state the number of logical CPUs M.
  4. The result. The numbers. A table or a plot, not a screenshot.
  5. The interpretation. What the numbers show, and what they do not. In particular, explain what happens when N > M: are the extra processes still concurrent? Are they parallel? What is the relationship between the two concepts in your data?
  6. What did not work. At least one thing you tried that failed, and what you learned from the failure.

The last item is required and is graded. A presentation with no failure to report is incomplete.

Grading

Each part is graded on (a) whether the hypothesis is falsifiable, (b) whether the measurement actually tests it, and (c) whether the interpretation distinguishes what the data shows from what it does not. A working demo with no measurement receives partial credit; a measurement with no interpretation receives partial credit.