Skip to content

Commit

Permalink
Add multi.py and Modify CSAPP Labs
Browse files Browse the repository at this point in the history
  • Loading branch information
huangrt01 committed Jun 30, 2020
1 parent 0c0e28b commit 0d52c88
Show file tree
Hide file tree
Showing 13 changed files with 843 additions and 6 deletions.
Binary file modified .DS_Store
Binary file not shown.
Binary file modified Notes/.DS_Store
Binary file not shown.
2 changes: 2 additions & 0 deletions Notes/C++.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ C不能用for(int i=0; ; ) 需要先定义i

Dijkstra反对goto的[文章](http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF)

getopt函数处理参数,用法参照[tsh.c](https://github.com/huangrt01/CSAPP-Labs/blob/master/shlab-handout/tsh.c)

##### 结构体

结构体内存分配问题:内存对齐
Expand Down
29 changes: 28 additions & 1 deletion Notes/CSAPP-Labs.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
## CSAPP-Labs

[我的CSAPP-Labs实现](https://github.com/huangrt01/CSAPP-Labs)

- [x] Data Lab
- [x] Shell Lab (plus [OSTEP shell lab](https://github.com/remzi-arpacidusseau/ostep-projects/tree/master/processes-shell))

### Data Lab

#### Integer

##### bitXor(x,y)
Expand Down Expand Up @@ -255,6 +261,27 @@ command分为两类
* the pathname of an executable file: forks a child process
* **job**的概念,指代initial child process,job用PID或JID标识,JID由`%`开头

The parent needs to block the SIGCHLD signals in this way in order to avoid the **race condition** where the child is reaped by sigchld handler(and thus removed from the job list) before the parent calls addjob.

**BUG**

有signal时,getc()可能会有很奇怪的bug,不会返回EOF,最终影响fgets的行为,太坑了!!!具体来说,注释掉eval(cmdline)这一行读取文件则不会出错,最终的解决方案是先把文件整体读入内存...... bug留存进了branch getc_error分支

**Bonus**:

current Built-in commands:

* exit/quit
* cd
* pwd
* jobs
* bg/fg
* path: The `path` command takes 0 or more arguments, with each argument separated by whitespace from the others. A typical usage would be like this: `wish> path /bin /usr/bin`, which would add `/bin` and `/usr/bin` to the search path of the shell. If the user sets path to be empty, then the shell should not be able to run any programs (except built-in commands). The `path` command always overwrites the old path with the newly specified path.

based on the needs of [OSTEP Projects](https://github.com/remzi-arpacidusseau/ostep-projects/tree/master/processes-shell), additionally implement the following features:

* Wrong input error
* Paths
* Redirection
* Parallel commands

The parent needs to block the SIGCHLD signals in this way in order to avoid the **race condition** where the child is reaped by sigchld handler(and thus removed from the job list) before the parent calls addjob.
56 changes: 54 additions & 2 deletions Notes/OSTEP-Operating-Systems-Three-Easy-Pieces.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,59 @@ NOTE:
* [why index-0?](https://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF)
#### 10.Multiprocessor Scheduling (Advanced)
* 概念:multicore processor threads
* 还没看
* 概念:multicore processor 与threads配合
##### CRUX: how to schedule jobs on multiple CPUs
**Background: Multiprocessor Architecture**
单核与多核的区别:the use of hardware caches(e.g., Figure 10.1), and exactly how data is shared across multiple processors.
Q: cache coherence问题,不同CPU的cache未及时更新,导致读错数据
A: 利用hardware, by monitoring memory accesses: bus snooping; write-back caches
**Don’t Forget Synchronization**
虽然解决了coherence问题,依然需要mutual exclusion primitives(locks)
**One Final Issue: Cache Affinity**
**Single-Queue Scheduling**
SQMS (single-queue multiprocessor scheduling),存在的问题如下:
* lack of scalability: lock overhead随CPU数目增加而变高
* cache affinity: 需要用复杂的机制调度,比如将少量jobs migrating from CPU to CPU
->
MQMS (multi-queue multiprocessor scheduling): 分配jobs给CPU
* 优点:more scalable; intrinsically provides cache affinity
* 缺点:load imbalance
##### CRUX: how to deal with load imbalance?
migration: 将余数migrate
the tricky part: how should the system decide to enact such a migration?
e.g. work stealing: source queue经常peek其它的target queue,使两边work load均衡
* peek频率是超参数,过高会失去MQMS的意义,过低会有load imbalances
**Linux Multiprocessor Schedulers**
O(1) scheduler: priority-based scheduler
CFS (Completely Fair Scheduler): a deterministic proportional-share approach
BFS (BF Scheduler): also proportional-share, but based on a more complicated scheme known as Earliest Eligible Virtual Deadline First (EEVDF)
* BFS是single queue,前两个是multiple queues
#### 11.summary
Expand Down Expand Up @@ -1711,3 +1762,4 @@ Separate Compilation: -c, 只产生object file, 不link, 后面联合link-editor
inbox:
* hm5.8 g++ hm5.8.cpp -o hm5.8 -Wall && "/Users/huangrt01/Desktop/OSTEP/ostep-code/cpu-api/“hm5.8 同一个命令,用coderunner输出六行,用terminal输出五行
* 19.physically-indexed cache
Binary file modified Notes/OSTEP-Operating-Systems-Three-Easy-Pieces/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@

Welcome to multi.py, a rudimentary multi-CPU scheduling simulator. This
simulator has a number of features to play with, so pay attention! Or don't,
because you are lazy that way. But when that exam rolls around...

To run the simulator, all you have to do is type:

prompt> ./multi.py

This will then run the simulator with some random jobs.

Before we get into any such details, let's first examine the basics of such a
simulation.

In the default mode, there are one or more CPUs in the system (as specified
with the -n flag). Thus, to run with 4 CPUs in your simulation, type:

prompt> ./multi.py -n 4

Each CPU has a cache, which can hold important data from one or more running
processes. The size of each CPU cache is set by the -M flag. Thus, to make
each cache have a size of '100' on your 4-CPU system, run:

prompt> ./multi.py -n 4 -M 100

To run a simulation, you need some jobs to schedule. There are two ways to do
this. The first is to let the system create some jobs with random
characteristics for you (this is the default, i.e., if you specify nothing,
you get this); there are also some controls to control (somewhat) the nature
of randomly-generated jobs, described further below. The second is to specify
a list of jobs for the system to schedule precisely; this is also described in
more detail below.

Each job has two characteristics. The first is its 'run time' (how many time
units it will run for). The second is its 'working set size' (how much cache
space it needs to run efficiently). If you are generating jobs randomly, you
can control the range of these values by using the -R (maximum run-time flag)
and -W (maximum working-set-size flag); the random generator will then
generate values that are not bigger than those.

If you are specifying jobs by hand, you set each of these explicitly, using
the -L flag. For example, if you want to run two jobs, each with run-time of
100, but with different working-set-sizes of 50 and 150, respectively, you
would do something like this:

prompt> ./multi.py -n 4 -M 100 -L 1:100:50,2:100:150

Note that you assigned each job a name, '1' for the first job, and '2' for the
second. When jobs are auto-generated, names are assigned automatically (just
using numbers).

How effectively a job runs on a particular CPU depends on whether the cache of
that CPU currently holds the working set of the given job. If it doesn't, the
job runs slowly, which means that only 1 tick of its runtime is subtracted
from its remaining time left per each tick of the clock. This is the mode
where the cache is 'cold' for that job (i.e., it does not yet contain the
job's working set). However, if the job has run on the CPU previously for
'long enough', that CPU cache is now 'warm', and the job will execute more
quickly. How much more quickly, you ask? Well, this depends on the value of
the -r flag, which is the 'warmup rate'. Here, it is something like 2x by
default, but you can change it as needed.

How long does it take for a cache to warm up, you ask? Well, that is also set
by a flag, in this case, the -w flag, which sets the 'warmup time'. By
default, it is something like 10 time units. Thus, if a job runs for 10 time
units, the cache on that CPU becomes warm, and then the job starts running
faster. All of this, of course, is a gross approximation of how a real system
works, but that's the beauty of simulation, right?

So now we have CPUs, each with caches, and a way to specify jobs. What's left?
Aha, you say, the scheduling policy! And you are right. Way to go, diligent
homework-doing person!

The first (default) policy is simple: a centralized scheduling queue, with a
round-robin assignment of jobs to idle CPUs. The second is a per-CPU
scheduling queue approach (turned on with -p), in which jobs are assigned to
one of N scheduling queues (one per CPU); in this approach, an idle CPU will
(on occasion) peek into some other CPU's queue and steal a job, to improve
load balancing. How often this is done is set by a 'peek' interval (set by the
-P flag).

With this basic understanding in place, you should now be able to do the
homework, and study different approaches to scheduling. To see a full list of
options for this simulator, just type:

prompt> ./multi.py -h
Usage: multi.py [options]

Options:
Options:
-h, --help show this help message and exit
-s SEED, --seed=SEED the random seed
-j JOB_NUM, --job_num=JOB_NUM
number of jobs in the system
-R MAX_RUN, --max_run=MAX_RUN
max run time of random-gen jobs
-W MAX_WSET, --max_wset=MAX_WSET
max working set of random-gen jobs
-L JOB_LIST, --job_list=JOB_LIST
provide a comma-separated list of
job_name:run_time:working_set_size (e.g.,
a:10:100,b:10:50 means 2 jobs with run-times of 10,
the first (a) with working set size=100, second (b)
with working set size=50)
-p, --per_cpu_queues per-CPU scheduling queues (not one)
-A AFFINITY, --affinity=AFFINITY
a list of jobs and which CPUs they can run on (e.g.,
a:0.1.2,b:0.1 allows job a to run on CPUs 0,1,2 but b
only on CPUs 0 and 1
-n NUM_CPUS, --num_cpus=NUM_CPUS
number of CPUs
-q TIME_SLICE, --quantum=TIME_SLICE
length of time slice
-P PEEK_INTERVAL, --peek_interval=PEEK_INTERVAL
for per-cpu scheduling, how often to peek at other
schedule queue; 0 turns this off
-w WARMUP_TIME, --warmup_time=WARMUP_TIME
time it takes to warm cache
-r WARM_RATE, --warm_rate=WARM_RATE
how much faster to run with warm cache
-M CACHE_SIZE, --cache_size=CACHE_SIZE
cache size
-o, --rand_order has CPUs get jobs in random order
-t, --trace enable basic tracing (show which jobs got scheduled)
-T, --trace_time_left
trace time left for each job
-C, --trace_cache trace cache status (warm/cold) too
-S, --trace_sched trace scheduler state
-c, --compute compute answers for me

Probably the best to learn about are some of the tracing options (like -t, -T,
-C, and -S). Play around with these to see better what the scheduler and
system are doing.








Loading

0 comments on commit 0d52c88

Please sign in to comment.