CSCI402 Multi-threading - Token Bucket Emulation in C
Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit
CSCI402
Warmup Assignment #2
(100 points total)
Multi-threading -Token Bucket Emulation in C
Due 11:45PM 9/29/2023(firm)
[ This content is protected and may not be shared, uploaded, or distributed.]
This spec is private (i.e., only for students who took or are taking CSCI 402 at USC). You do not have permissions to display this spec at a public place (such as a public bitbucket/github). You also do not have permissions to display the code you write to implementation this spec at a public place since your code was written to implement a private spec.(If a prospective employer asks you to post your code, please tell them that you do not have permissions to do so; but you can send them a
private copy.)
To download the spec below in one command (so you can make a backup of the spec in case the class web server is not available due to network or server problem), do the following inside a terminal in
Ubuntu 16.04 (preferable in an empty directory) to make a quick and dirty (may be incomplete)
backup of our spec:
wgeth(-)t(r)tp(-1):/(1)/m(--)e(u)r(s)lot(er=)u(U)s(S)c e(ER)du(ID)/cs(--p)40(ass)2w-f2(or)3(d)projects(PASSW)/w(OR)ar(D)\mup2/index.html
where USERID and PASSWORD are the user ID and password used to access protected content from our class web site. Then type the following in the terminal:
firefox merlot.usc.edu/cs402-f23/projects/warmup2/index.html
Please remember that I do update the spec occasionally. You should ONLY look at your backup copy when the class web site is unavailable.
Assignment Description
(Please check out the Warmup 2 FA O before sending your questions to the TAs, the course producers, or the instructor:)
In this assignment, you will emulate/simulate a traffic shaper that transmits/services packets
controlled by a token bucket filter depicted below using multi-threading within a single process. If you are not familiar with pthreads, you should read Chapter 2 of our required textbook .
IMPORTANT: Please note that this assignment is posted before all the background materials (e.g., Unix signals) have been covered in lectures. If you do not want to learn about these components on your own (by learning from the textbook), please delay starting this project until they are covered in class. There will be plenty of time to implement this project after the relevant topics are covered in
class. If you don't want to wait and don't want to learn about Unix signals and stuff on your own,I
would strongly recommend that you do this assignment in two steps. First, you write your code to do the emulation without any
we would have covered everything you need to finish the assignment. Then you follow the recommendations in the lecture to add
Figure 1 above depicts the system you are required to emulate. The token bucket has a capacity
(bucket depth) of B tokens. Tokens arrive into the token bucket according to an unusual arrival process
where the inter-token-arrival time between two consecutive tokens is 1/r. We will call r the token
arrival rate (although technically speaking, it's not exactly the token arrival rate; please understand that this is quite different from saying that the tokens arrive at a constant rate of r). Extra tokens
(overflow) would simply disappear if the token bucket is full. A token bucket, together with its control mechanism, is referred to as a token bucket filter.
Packets arrive at the token bucket filter according to an unusual arrival process where the i nter-arrival time between two consecutive packets is 1/lambda. We will call lambda the packet arrival rate
(although technically speaking, it's not exactly the packet arrival rate; please understand that this is
quite different from saying that the packets arrive at a constant rate of lambda). Each packet requires p tokens in order for it to be eligiable for transmission.(Packets that are eligiable for transmission are
queued at the 2 facility.) When a packet arrives, if ai is not empty, it will just get queued onto the Q1
facility.(Please note that, in this case, you do not have to check if there is enough tokens in the
bucket so you can move the packet at the head of Q1 into Q2 and you need to understand why you do
not need to perform such a check.)Otherwise, it will check if the token bucket has p or more tokens in it. If the token bucket has p or more tokens in it, p tokens will be removed from the token bucket and the packet will join the Q2 facility (technically speaking, you are required to first add the packet to Q1
and timestamp the packet, remove the p tokents from the token bucket and the packet from Q1 and
timestamp the packet, before moving the packet into Q2), and wake up the servers in case they are
sleeping. If the token bucket does not have enough tokens, the packet gets queued into the Q1 facility.
Finally, if the number of tokens required by a packet is larger than the bucket depth, the packet must be dropped (otherwise, it will block all other packets that follow it).
The transmission facility (denoted as s1 and sz in the above figure and they are referred to as the
"servers") serves packets in Q2 in the first-come-first-served order and at a transmission/service rate of
mu per second. When a server becomes available, it will dequeue the first packet from Q2 and start transmitting/servicing the packet. When a packet has received 1/mu seconds of service, it leaves the system. You are required to keep the servers as busy as possible.
When a token arrives at the token bucket, it will add a token into the token bucket. If the bucket is
already full, the token will be lost. It will then check to see if oi is empty. If Q1 is not empty, it will see if there is enough tokens to make the packet at the head of qi be eligiable for transmission (packets in Q1 in also served in the first-come-first-served order). If it does, it will remove the corresponding
number of tokens from the token bucket, remove that packet from Q1 and move it into Q2, and wake up the servers in case they are sleeping. It will then check the packet that is now at the head of Q1 to see if it's also eligiable for transmission, and so on.
Technically speaking, the "servers" are not part of the "token bucket filter". Nevertheless, it's part of this assignment to emulation/simulation the severs because the servers are considered part of the
"system" to be emulated.(For the purpose of this spec, we will use the term "emulation" and "simulation" interchangeably.)
Our system can run in only one of two modes.
Deterministic :In this mode, all inter-arrival times are equal to 1/lambda seconds and all service times are equal to 1/mu seconds (both these values must be
rounded to the nearest millisecond), and all packets require exactly p tokens. If 1/lambda is greater than 10 seconds, please use an inter-arrival time of 10 seconds. If 1/mu is greater than 10 seconds, please use an
service time of 10 seconds.
Trace-driven :In this mode, we will drive the emulation using a trace specification file (will be referred to as a "tsfile"). Each line in the trace file specifies the inter-arrival time of a packet, the number of tokens it need in order for it to be eligiable for transmission, and its service time. (Please note that in this mode, it's perfectly fine if an inter-arrival time or a service time is greater than 10 seconds.) If you are running in the trace-drive mode, you must not validate or read the entire tsfile before you start your simulation.
In either mode, if 1/r is greater than 10 seconds, please use an inter-token-arrival time of 10 seconds. Otherwise, please round the inter-token-arrival time to the nearest millisecond.
Your job is to emulate the packet and token arrivals, the operation of the token bucket filter, the first- come-first-served queues Q1 and Q2, and servers s1 and s2. You also must produce a trace of your
emulation for every important event occurred in your emulation. Please see more details below for the requirements.
You must use:
· one thread for packet arrival
· one thread for token arrival
● one thread for each server
You must not use one thread for each packet.
In addition, you must use at least one mutex to protect Q1, Q2, and the token bucket.(It is recommended that you use exactly one mutex to protect Q1, Q2, and the token bucket.)
Finally, Q1 and Q2 must have infinite capacity (i.e., you should use My402List from warmup assignment #Hl to implement them and not use arrays).
We will not go over the slides for this assignment in class. Although it's important that you are familiar with it. Please read it over. If you have questions, please e-mail the instructor.
Compiling
Please use a Makefile so that when the grader simply enters:
make warmup2
an executable named warmup2 is created (minor variation is permitted if you document it). Please
make sure that your submission conforms to other general compilation requirements and README
requirements.
Commandline
The command line syntax (also known as "usage information") for warmup2 is as follows: warmup2 [-lambda lambda][-mu mu][-r r][-B B] [-P P][-n num][-t tsfile]
Square bracketed items are optional. You must follow the UNIX convention that commandline
options can come in any order.(Note: a commandline option is a commandline argument that begins with a - character in a commandline syntax specification.) Unless otherwise specified, output of your program must go to stdout and error messages must go to stderr.
The lambda, mu, r, B, and p parameters all have obvious meanings (according to the description above). The -n option specifies the total number of packets to arrive. If the -t option is specified, tsfile is a trace specification file that you should use to drive your emulation. In this case, you should ignore the -lambda,-mu,-P,a nd -n commandline options and run your emulation in the trace-driven mode. You may assume that tsfile conforms to the tracefile format specification.(This means that if you detect an error in this file, you may simply print an error message and call exit(). There is no need to
perform error recovery.) If the -t option is not used, you should run your emulation in the
deterministic mode.
The default value (i.e., if it's not specified in a commandline option) for lambda is 1 (packets per
second), the default value for mu is 0.35 (packets per second), the default value for r is 1.5 (tokens per second), the default value for B is 10 (tokens), the default value for p is 3 (tokens), and the default
value for num is 20 (packets). B, P, and num must be positive integers with a maximum value of 2147483647(0x7fffffff). lambda, mu, and r must be positive real numbers.
Running Your Code and Program Output
The emulation should go as follows. At emulation time 0, all 4 threads (arrival thread, token
depositing thread, and servers S1 and s2 threads) got started. The arrival thread would sleep so that it can wake up at a time such that the inter-arrival time of the first packet would match the specification (either according to lambda or the first record in a tracefile). At the same time, the token depositing
thread would sleep so that it can wake up at a time such that the inter-token-arrival time between
consecutive tokens is 1/r seconds and would try to deposit one token into the token bucket each time it wakes up. The actual arrival time of the first packet p1 is denoted as time T1, the actual arrival time of the 2nd packet p2 is denoted as time T2, and so on.
As a packet or a token arrives, or as a server becomes free, you need to follow the op erational rules of the token bucket filter. Since we have four threads accessing shared data structures, you must use the tricks you learned from Chapter 2 related lectures. Please also check out the slides for this assignment for the skeleton code for these threads.
You are required to produce a detailed trace for every important event occurred during the emulation
and every such event must be timestamped. Each line in the trace must correspond to one of the following situations:
· If a packet is served by a server (server s1 is assumed below for illustration), there must be exactly 7 output lines that correspond to this packet. They are:
p1 p1 p1 p1 p1 p1 p1
arrives, needs 3 tokens, inter-arrival time = 503. 112ms
enters Q1
leaves Q1, time in Q1 = 247.810ms, token bucket now has o token
enters Q2
leaves Q2, time in Q2 = 0.216ms
Please note the following:
o The value printed for "inter-arrival time" must equal to the timestamp of the "p1 arrives" event minus the timestamp of the "arrives" event for the previous packet.
o The value printed for "time in Q1" must equal to the timestamp of the "p1 leaves Q1" event minus the timestamp of the "p1 enters Q1" event.
o The value printed for "time in Q2" must equal to the timestamp of the "p1 leaves Q2" event minus the timestamp of the "p1 enters Q2" event.
o The value printed for "requesting ???ms of service" must be the requested service time (which must be an integer) of the corresponding packet.
o The value printed for "service time" must equal to the timestamp of the "p1 departs from S1" event minus the timestamp of the "p1 begins service at S1" event (and it
should be larger than the requested service time printed for the "begin service" event).
o The value printed for"time in system" must equal to the timestamp of the "p1 departs
from S1" event minus the timestamp of the "p1 arrives" event.
· If a packet is dropped, you must print:
p1 arrives, needs 3 tokens, inter-arrival time = 503.112ms, dropped
Please note that the value printed for "inter-arrival time" must equal to the timestamp of the "pl arrives" event minus the timestamp of the "arrives" event for the previous packet.
· If
SIGINT caught, no new packets or tokens will be allowed
Please understand that in order for the above to get printed correctly in a trace printout, using a
signal handler to catch signals may not work. You are strongly advised to use a separate SIGINT-catching thread and uses sigwait().
· If a packet is removed when it's in Q#(Q1 or Q2) because
must print:
p1 removed from Q#
· If a token is accepted, you must print:
token t1 arrives, token bucket now has 1 token
· If a token is dropped, you must print:
token t1 arrives, dropped
· When you are ready to start your emulation, you must print:
emulation begins
· When you are ready to end your emulation, you must print:
emulation ends
All the numeric values above are made up. You must replace them with the actual packet number,
actual number of tokens required, actual server number, measured inter-arrival time, measured time
spent in Ql, actual number of tokens left behind when a packet is moved into Q2, measured time spent in Q2, measured service time, and measured time in the system.
The output format of your program must satisfy the following requirements.
● You must first print all the emulation paramters. Please see the sample printout for what the output must look like.
· Whenever a token arrives, you must assign a number to it, and add it to the token bucket. You must then print its arrival time, the fact that it has arrived, and the number of tokens in the the token bucket. Please see the sample printout for what the output must look like.
· Whenever a packet arrives, you must assign a number to it. You must then print its arrival time, the fact that it has arrived, the number of tokens it needs for transmission, and the time between its arrival time and the arrival time of the previous packet. Please see the sample printout for
what the output must look like.
You then must append this packet onto Q1. Afterwards, you must then print the time this packet entered Q1 and the fact that it has entered Q1. Please see the sample printout for what the output must look like.
Later on, when this packet leaves Qi, it removes the correct number of tokens from the token
bucket. You must then print the time this packet leaves Q1, the fact that it has left Q1, the amount
of time it spent in 01, and the number of tokens in the the token bucket. Please see the sample printout for what the output must look like
You must then append this packet onto Q2. Afterwards, you must then print the time this packet
entered o2 and the fact that it has entered o2. Please see the sample printout for what the output
must look like
Later on, when this packet leaves Q2 and enters the server, you must then print which server the
packet entered, the time the packet begin service, the fact that it has begun service, and the
amount of time it spent in o2. Please see the sample printout for what the output must look like
● When emulation ends, you must print all the necessary statistics. Please see the sample printou for what the output must look like. If a particular statistics is not applicable (e.g., will caus
divide-by-zero error), instead of printing a numeric value, please print "N/A" followed by an explanation (such as, for example,"no packet was served"). Please note that your program
output must never contain any "Nan"(which means "not-a-number").
Below is an example what your program output must look like (please note that the values used here are just a bunch of unrelated random numbers for illustration purposes)
Emulation Parameters:
number to arrive = 20
lambda = 2 (print this line only if -t is not specified)
mu = 0.35 (print this line only if -t is not specified)
r = 4
B = 10
P = 3 (print this line only if -t is not specified)
tsfile = FILENAME (print this line only if -t is specified)
00000000.000ms: emulation begins
00000250.726ms: token t1 arrives, token bucket now has 1 token
00000501.031ms: token t2 arrives, token bucket now has 2 tokens
00000503. 112ms: p1 arrives, needs 3 tokens, inter-arrival time = 503. 112ms
00000503.376ms: p1 enters Q1
00000751. 148ms: token t3 arrives, token bucket now has 3 tokens
00000751. 186ms: p1 leaves Q1, time in Q1 = 247.810ms,token bucket now has o toker
00000752.716ms: p1 enters Q2
00000752.932ms: p1 leaves Q2, time in Q2 = 0.216ms
00000752.982ms: p1 begins service at S1, requesting 2850ms of service
00001004.271ms: p2 arrives, needs 3 tokens, inter-arrival time = 501. 159ms
00001004.526ms: p2 enters Q1
00001005.615ms: token t4 arrives, token bucket now has 1 token
00001256.259ms: token t5 arrives, token bucket now has 2 tokens
00001505.986ms: p3 arrives, needs 3 tokens, inter-arrival time = 501.715ms
00001506.713ms: p3 enters Q1
00001507.552ms: token t6 arrives, token bucket now has 3 tokens
00001508.281ms: p2 leaves Q1, time in Q1 = 503.755ms, token bucket now has o token 00001508.761ms: p2 enters Q2
00001508.874ms: p2 leaves Q2, time in Q2 = 0. 113ms
00001508.895ms: p2 begins service at S2, requesting 1900ms of service
00003427.557ms:p2 departs from S2, service time = 1918.662ms, time in system = 2423.286ms 00003612.843ms: p1 departs from S1, service time = 2859.861ms, time in system = 3109.731ms
????????.???ms: p20 departs from S?, service time =???.???ms, time in system=???.???ms
????????.???ms:emulation ends
Statistics:
average average
average average average average
packet packet
number
number
number
number
inter-arrival service time
of of of of |
packets packets packets packets |
in in at at |
time =
=
Q1 =
Q2 =
S1 =
S2 =
average time a packet spent in system =
standard deviation for time spent in system =
packet drop probability =
In the Emulation Parameters section, please print the emulation parameters specified by the user or the default values mentioned above. Please do not print the "adjusted" values because certain parameters are too small.(For example, if lambda is 0.01, you must print 0.01 and not 0.1.)
After Emulation Parameters section comes the Event Trace section. The first column there contains
timestamps and they correspond to event times, measured relative to the start of the emulation. Every emulation event must be timestampted. You need to figure out how to make sure that the timestamp
values look reasonable (e.g., never decrease in value). Please use 8 digits (with leading zeroes) to the left&n
2023-09-27