CSCB09 A1 && A3
Because in A1 and A3, there are the same information gathering but different with the calculating. Thus, I use the information gather part from Part I. However, i add how to compile A3, and what difficulties in the below.
Reading through the documentation for the auxiliray C libraries listed in the assignment handout, I determined which functions I can use to gather all the required stat (running parameters, user usage, system usage, system informtaion).
- To get the system information, I created the
utsname
struct defined in<sys/utsname.h>
and got the required information using theusname()
function. The following fields in the struct were useful for this assignment:sysname
: system namenodename
: machine nameverson
: OS versionrelease
: OS releasemachine
: machine architecture
- To get the system informtaion about the
System running since last reboot
, I read through the/proc/uptime
file, got the first parameter in this file and performed the calculation in Step 2.
- There are some default value for this assignment like
sample = 10
andtime delay = 1
:sample
: the default value is 10, can be changed by commandtime delay
: the default value is 1, can be changed by commandmemory self-utilization
: how much memory the monitoring tool is actually using
- To get the value of
memory self-utilization
(in KB), I used theru_maxrss
field from therusage
struct defined insys/resource.h
and got this informtaion required using thegetusage()
function.
- To get the user usage information, I used the
utmp
struct defined inutmp.h
and got this required stat using thegetutent
function. The following fields in the struct were necessary for this assignment:ut_user
: the user log-in nameut_line
: the device namehost
: the host name
- To get the number of CPU cores, I called the
sysconf(_SC_NPROCESSORS_ONLN)
function fromunistd.h
. - To get the total CPU usage, I read through the
/proc/stat
file and performed the calculations outlined in Step 2. - To get the amount of memory used (physical and virtual), I used the
sysinfo
struct defined insys/sysinfo.h
and got this required stat using thesysinfo()
function. The following fields from thesysinfo
struct were necessary for the purposes of this assignment:totalram
: the total usable main memory sizefreeram
: the available memory spacetotalswap
: the total swap space sizefreeswap
: the size of the swap space still availablemem_unit
: the memory unit size in bytes
- To get the CPU Usage, it required two time points:
`CPU Usage (%) = 100 - (idle_2 - idle_1) * 100.0 / (totalTime_2 - totalTime_1)`
Note: the subscript 1 denotes the value at the first time point and the subscript 2 denotes the value at the second time point.
The total time can be calculated be summing all the values in the first line of the /proc/stat
file and the idle time is the fourth number on the first
- To get the Memory Usage, it required many parameters and formulas:
total physical memory
= (total ram)total virtual memory
= (total ram) + (total swap space)physical memory used
= (total ram) - (free ram)swap space used
= (total swap space) - (free swap space)virtual memory used
= (physical memory used) + (swap space used)
- I created two complex struct type called
CPU_OCCUPY
andMEMORY_OCCUPY
to store eachMemory usage
data andCPU usage
data. - For each type of node, I also created two Arrays to store each nodes represented different value in different time points.
- Each node contained all the relevant stat.
I iterated through argv
to get access to the command line arguments entered by the user. Since some choses
have a =
sign in the middle, I used strtok()
from string.h
to split each argument at =
. This way, we can read the chose
name and the value inputted (if applicable separately). If the string after the =
cannot be converted to an integer, an error message will appear and the program will terminate. To decide which chose
have been inputted by the user, I used strcmp()
from string.h
and used boolean variables to store whether or not each chose
has been inputted. Depending on which combination of chose
have been inputted, the program prints the relevant stat (through a series of if
/else
statements.)
To ensure that the output is refreshed at every time point, before taking each sample, I saved the position of the cursor using the \x1b[s
(which used to save the current cursor position in a terminal emulator) escape code. After printing out the relevant information using the functions described below, I used the \x1b[u
(restores the cursor to the previously saved position) escape code to allow for the cursor to return to previously saved position. In the next iteration, the previous output is overwritten. In this way, the output refreshes at every time point.
Function | Description |
---|---|
MEMORY_OCCUPY* newMemory() |
Creats a new Memory Node containd all relevant stat which record the data in different time points. |
CPU_OCCUPY *newCpu() |
Creats a new Memory Node containd all relevant stat which record the data in different time points. |
float calculateCPUUsage(CPU_OCCUPY *cpuinfo_1, CPU_OCCUPY *cpuinfo_2) |
Returns CPU usage as a percentage. cpuinfo_1 and cpuinfo_2 represent the first time points' CPU usage and the second time points' CPU usage. |
bool isInteger(char *string) |
Returns true iff the string s is an integer. |
void printMemoryUsage() |
Print the relevant stat about Memory Usage in specific format. |
MEMORY_OCCUPY *generateMemoryUsage(MEMORY_OCCUPY **MEMORY_array, int i, int sample) |
Return the MEMORY_OCCUPY type which contains all stat in new time point and print the total memory usage in specific format. |
MEMORY_OCCUPY *generateMemoryUsageSequence(MEMORY_OCCUPY **MEMORY_array, int i, int sample) |
Return the MEMORY_OCCUPY type which contains all stat in new time point and print the total memory usage in specific format under the command --sequential |
CPU_OCCUPY *generateCPUUsage(CPU_OCCUPY **CPU_array, int i) |
Return the CPU_OCCUPY type which contains all stat in new time point and print the CPU usage in specific format tip: because the first time only has one information, the CPU usage is meaningless! |
bool changeArgument(int argc, char**argv, int *sample, int *interval, bool *system_chose, bool *graph_chose, bool *user_chose, bool *sequential_chose |
Parses through command line arguments to determine which flags have been entered. Returns true iff arguments are entered in correct format. argc is the number of command line arguments entered and argv is an array of strings that holds the command line arguments entered. sample points to the number times statistics will be collected and interval points to the frequency of statistic collection. system_chose , user_chose and graphics_chose each point to a boolean variables that holds true iff the system chose, user chose, graphics chose, sequential_chose are inputted by the user, respectively. |
void getUserUsage() |
Print some relevant stat about user usage. |
void getUptime() |
Calculate the uptime parameter and print it to the screen in specific format. |
void printSystemInfo() |
Print all stat about the system information. |
void printSystemStats(int sample, int inerval, bool system_chose, bool graph_chose, bool user_chose, bool sequential_chose) |
Prints final output. sample is the number times statistics will be collected and interval is the frequency of statistic collection.system_chose , user_chose , graph_chose and sequential_chose hold true iff the system chose, user chose, graphics and 'sequential` chose are inputted by the user, respectively. |
void printSystemStatsSequence(int sample, int inerval, bool system_chose, bool graph_chose, bool user_chose, bool sequential_chose) |
Prints final output. sample is the number times statistics will be collected and interval is the frequency of statistic collection.system_chose , user_chose , graph_chose and sequential_chose hold true iff the system chose, user chose, graphics and 'sequential` chose are inputted by the user, respectively. |
MEMORY_OCCUPY *generateMemoryUsageGraphics(MEMORY_OCCUPY **MEMORY_array, int i, int sample) |
Displays memory usage with graphics. sample is the number times statistics will be collected, i indicates the number times statistics will have been collected by the end of the current cycle, MEMORY_array represents all memory information in this reading |
MEMORY_OCCUPY *generateMemoryUsageSequence(MEMORY_OCCUPY **MEMORY_array, int i, int sample) |
this is as same as MEMORY_OCCUPY *generateMemoryUsageGraphics(MEMORY_OCCUPY **MEMORY_array, int i, int sample) but under "--sequential" condition |
CPU_OCCUPY *generateCPUUsageGraphics(CPU_OCCUPY **CPU_array, int i) |
Displays CPU usage with graphics. sample is the number times statistics will be collected, i indicates the number times statistics will have been collected by the end of the current cycle, CPU_array represents all memory information in this reading |
CPU_OCCUPY *generateCPUUsageGraphicsSequence(CPU_OCCUPY **CPU_array, int i, int sample) |
Displays CPU usage with graphics. sample is the number times statistics will be collected, i indicates the number times statistics will have been collected by the end of the current cycle, CPU_array represents all memory information in this reading under --sequential |
Function | Description |
---|---|
COMMAND *package(int sample, int t_delay) |
Creates and initializes a COMMAND structure and returns a pointer to it. |
void changeArgument(int argc, char **argv, COMMAND *command) |
Parses command-line arguments and updates command structure flags accordingly. |
void Pressed_ctr_c() |
Signal handler for SIGINT (Ctrl+C) signal.Prompts the user to confirm program termination. |
void generateCPUUsage(int i, double *cpu, double *TIME_pre, double *UT_pre, COMMAND *command, char CPU_arr_3[][1024], char CPU_arr_4[][1024], char CPU_str[1024]) |
Reads CPU usage information from /proc/stat, calculates CPU usage percentage,and generates formatted strings for CPU usage data. |
void printMemoryStats(COMMAND *command, int i, double *preVirMem, char arr[1024]) |
Retrieves memory usage statistics using sysinfo() and formats the data. |
void printMemoryInfo(int i, COMMAND *command, char memory_arr[][1024]) |
Prints memory usage information. |
void printCores() |
Prints the number of CPU cores. |
void getUserUsage(char USER_arr[1024]) |
Retrieves user session information and formats the data. |
bool isInt(char *string) |
Checks if a string represents an integer. |
void printSystemStats(COMMAND *command) |
Prints system statistics based on command flags and arguments. |
void getUptime() |
Reads system uptime information from /proc/uptime and prints it. |
void printSystemInfo() |
Prints system information such as system name, machine name, version, release, architecture, and uptime. |
void printCPUInfo(int i, COMMAND *command, char CPU_arr_0[][1024]) |
Prints CPU usage information. |
void printUserTitle() |
Prints a title for user session information. |
- Navigate to the directory (i.e.,
cd
) in whichMySystemStats.c
is saved on your machine. - In the terminal, enter
gcc -Wall -Werror mySystemStats.c -o MySystemStats
to compile the Part I and entermake
to compile Part II, which is the concurrency program. - To execute the program, enter
./MySystemStats
for Part I and./a3
for Part II into the terminal. You may also use the following flags when executing:
Flag | Description |
---|---|
--system |
to indicate that only the system usage should be generated |
--user |
to indicate that only the users usage should be generated |
--graphics or -g |
to include graphical output in the cases where a graphical outcome is possible as indicated below |
--sequential |
to indicate that the information will be output sequentially without needing to "refresh" the screen (useful if you would like to redirect the output into a file) |
--samples=N |
if used the value N will indicate how many times the statistics are going to be collected and results will be average and reported based on the N number of repetitions.If not value is indicated the default value will be 10 |
--t_delay=T |
to indicate how frequently to sample in seconds. If not value is indicated the default value will be 1 sec |
samples t_delay |
The last two arguments can also be considered as positional arguments if not flag is indicated in the corresponding order |
- For example,
./MySystemStats --system --g --samples=5 --t_delay=2
will print the system usage report with graphics and will collect statistics every 2 seconds for a total and of 5 time points. - The number of samples and frequency can also be inputted as positional arguments (i.e., as two adjacent numbers separated by a space, where the first number is the number of samples and the second number is the frequency).
- These positional arguments can be located anywhere along the input as long as the two numbers are adjacent (e.g.,
./MySystemStats 5 --system 2
is invalid). - For example,
./MySystemStats --user 5 2
and./MySystemStats 5 2 --system
will both print the system information report and will collect statistics every 2 seconds for a total of 5 time points. - For Part II, you also can individually type the number. The program will automatically recognize the first one is sample and second one is tdelay.
./MySystemStats
is equivalent to./mySystemStats --system --user --samples=10 --t_delay=1
.
- These positional arguments can be located anywhere along the input as long as the two numbers are adjacent (e.g.,
- If
Invalid argument entered!
is printed on the screen after executing, refer back to flags outline in Step 3 and repeat the above steps.
This section applies if the user inputs the graphics flag (i.e., --graphics
or --g
).
Memory Usage Graphics: The graphics are a display of delta_memory_usage
, the relative change in physical memory usage between the previous and current samples. If delta_memory_usage
is negative, there is a : symbol for every change of 0.01 with a @ at the end. If deltaMemoryUsage is positive, there is a # symbol for every change of 0.01 with a * at the end. If deltaMemoryUsage is 0.00, a o is printed. Beside this graphic is an expression of the form delta_memory_usage
, where totalMemoryUsed is expressed in GB.
CPU Usage Graphics:
- If the CPU usage is 0%, the
|||
symbol is printed. If the CPU usage is positive, a|
is printed for every percent of usage (rounded up to the nearest percent). - For part II, there will be nothing is the usage is 0%.
Sample Graphics: it is the approximately graph, the output is some different with it.
Nbr of samples: 10 -- every 1 secs
Memory usage: 4052 kilobytes
---------------------------------------
### Memory ### (Phys.Used/Tot -- Virtual Used/Tot)
9.75 GB / 15.37 GB -- 9.75 GB / 16.33 GB |o 0.00 (9.75)
9.75 GB / 15.37 GB -- 9.75 GB / 16.33 GB |* 0.00 (9.75)
9.75 GB / 15.37 GB -- 9.75 GB / 16.33 GB |* 0.00 (9.75)
9.76 GB / 15.37 GB -- 9.76 GB / 16.33 GB |* 0.00 (9.76)
9.85 GB / 15.37 GB -- 9.85 GB / 16.33 GB |#########* 0.09 (9.85)
10.06 GB / 15.37 GB -- 10.06 GB / 16.33 GB |####################* 0.20 (10.06)
10.13 GB / 15.37 GB -- 10.13 GB / 16.33 GB |#######* 0.07 (10.13)
10.16 GB / 15.37 GB -- 10.16 GB / 16.33 GB |##* 0.03 (10.16)
10.28 GB / 15.37 GB -- 10.28 GB / 16.33 GB |###########* 0.12 (10.28)
10.38 GB / 15.37 GB -- 10.38 GB / 16.33 GB |##########* 0.11 (10.38)
---------------------------------------
### Sessions/users ###
marcelo pts/0 (138.51.12.217)
marcelo pts/1 (tmux(277015).%0)
alberto tty7 (:0)
marcelo pts/2 (tmux(277015).%1)
marcelo pts/5 (138.51.12.217)
---------------------------------------
Number of cores: 4
total cpu use = 15.57%
||| 0.25
||||||||| 6.93
||||||||||||||| 12.08
|||||||||||||||| 13.83
||||||||| 6.41
|||||||||||||||| 13.97
|||||||||||||||||| 15.37
||||||||||||||||| 14.91
||||||||||||||||||| 16.34
|||||||||||||||||| 15.57
---------------------------------------
### System Information ###
System Name = Linux
Machine Name = iits-b473-01
Version = #99-Ubuntu SMP Thu Sep 23 17:29:00 UTC 2021
Release = 5.4.0-88-generic
Architecture = x86_64
System running since last reboot: 3 days 19:27:30 (91:27:30)
---------------------------------------
Potential Technical Difficulties:
-
If there are too many information output in terminal, the formatting for the graphics may not be as desired. If this occurs, kindly using the terminal command
clear
and rerun the program. -
Part II need us to calculate the CPU usage concurrently. So, in this part, the program need to use the
pipe
andfork
to creat the child process for each part, such asmemory
,cpu
anduser
. Thus, that is why there is astat_func_child[3]
. -
By using the
pipe
to change the program, it need to pipe the value between each so it leads to change many original function with the Part I. In Part I, I have use many stat_function dirctly print the information. However, in Part II, i change the orginal fucntion and revise them to revise the string Array to store the message. In the simple words, i separate theprint part
andhandle information part
. -
In this assignment, it has a requirment about the "We will compare the total runtime of your program using the time command, and it should not exceed for more than 1% the one given by
tdelay
*samples
". This is very difficult to do. The biggest part I change is the code in theprintSystemStats
last part to print the each information, i have tried the origin part in Part I but it cost approximately one more times(like 10 sample 1 tdelay using the 20s). -
Another part is when i calculate the cpu usage. i read each stats by
stroken
which is as same as Part I but is cost more time like 0.3s or 0.4s and sometimes cause segment fault. I still don't know the reason.