[Operating system] Disk scheduling algorithms (FCFS, SSTF, SCAN and C-LOOK scheduling strategies)

Lab Week 18 Lab Report

Experiment content: hard disk scheduling

  • Write a C program to simulate the hard disk head scheduling algorithm in the courseware Lecture25, including
    • FCFS, SSTF, SCAN and C-LOOK scheduling strategies.
    • Fixed a hard disk cylinder number;
    • Input a batch of random hard disk cylinder request sequences, and calculate the average total moving distance of the head under each scheduling strategy (assuming that the head moves at an ideal uniform speed, the moving distance can be regarded as the moving time, and the total time is divided by the number of requests to get the average Response time).
  • Analyze the above experimental results.

I. Hard Disk Head Scheduling Algorithm

Because memory is usually too small to hold all data and programs permanently, computer systems must provide external memory to back up memory. Modern computer systems use magnetic disks (hard disks) as the primary online storage medium for information (programs and data). In other words, hard disks or magnetic disks provide a large amount of external storage for modern computer systems.

image-20220612203712999

A magnetic disk is a physical disk coated with a magnetic substance on the surface. Data is accessed from the disk through a magnetic head (conductor coil). During reading/writing, the magnetic head is fixed and the disk rotates at a high speed underneath. Data on a disk's surface is stored in a set of concentric circles called tracks. Each track is as wide as the magnetic head, and there are thousands of tracks on a platter. The track is divided into hundreds of sectors, and each sector has a fixed storage size, so the inner sector has a higher density.

The disk address is represented by (cylinder number, disk number, sector number).

One of the responsibilities of the operating system is to use the hardware efficiently. For disk drives, meeting this requirement has faster access speeds and wider disk bandwidth.

For disk, access time consists of two main components:

  • Seek time : It is the time for the magnetic arm to move the head to the cylinder containing the target sector;
  • Rotational delay: is the extra time for the disk to rotate the target sector to under the head;

In this part, we optimize the seek time, and analyze the optimization situation through different head scheduling algorithms.

1. First Come First Served (FCFS) algorithm

The FCFS algorithm schedules according to the order in which processes request access to disks. This is the simplest disk scheduling algorithm. Although this algorithm is fair, it usually does not provide the fastest service.

image-20220612202539690

Implementation code:

//设置磁道请求
void set_request(int *cylinders, int *request, int req_num){
    
    
    for(int i = 0; i < req_num; i++){
    
    
        int req_id = request[i];
        cylinders[req_id]++; //对应的磁道请求数加1
    }
}

Code description:

This function sets the request for the cylinders of the track table. If there is a request for the track, add one to the corresponding entry value, and so on;

void FCFS(int head, int *request, int *cylinders, int req_num){
    
    
    printf("===============FCFS=============\n");
    int move_sum = 0;
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);//设置磁道请求
    printf("Head location: %d\n", head);
    printf("Processing sequence: ");
    printf("%d ", head);
    for(int i = 0; i < req_num; i++){
    
    
        int req_id = request[i];
        printf("%d ", req_id);
        cylinders[req_id]--;
        move_sum += abs(head - req_id); //计算移动距离
        head = req_id; //磁头移动
    }
    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));


}

Code description:

According to the principle of FCFS scheduling algorithm, directly process the request sequence from beginning to end, and calculate the moving distance of the magnetic head and the average response time;

Experimental results:

the queue with requests for cylinders: 98 183 37 122 14 124 65 67

the head's position of cylinder: 53

image-20220614200244809

2. Shortest Seek Time First (SSTF) algorithm

SSTF always chooses the track closest to the track where the current head is located, so that the time for each seek is the shortest. It may be reasonable to process all requests close to the current head position before moving the head elsewhere to process other requests.

The defect of this algorithm is that if requests are frequently added near a certain magnetic head, then the magnetic head will work in this vicinity for a long time, resulting in an indefinite delay of further tracks, that is, "starvation".

image-20220612202738613

Implementation code:

void SSTF(int head, int *request, int *cylinders, int req_num){
    
    
    printf("===============SSTF=============\n");
    int move_sum = 0;
    int dis_list[req_num];
    int dis_idx[req_num];
    int init_head = head;
    for(int i = 0; i < req_num; i++){
    
    
        int dis = abs(head - request[i]);
        dis_list[i] = dis;
        dis_idx[i] = i;
    }
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
    printf("Head location: %d\n", head);
  
    //对dis_list从小到大进行排序,作为磁道请求序列
    for(int i = 0; i < req_num - 1; i++){
    
    
        for(int j = 0; j < req_num - i - 1; j++){
    
    
            if(dis_list[j] > dis_list[j+1]){
    
    
                int temp = dis_list[j];
                int temp_idx = dis_idx[j];
                dis_list[j] = dis_list[j+1];
                dis_idx[j] = dis_idx[j+1];
                dis_list[j+1] = temp;
                dis_idx[j+1] = temp_idx;
            } 
        }
    }
    printf("Processing sequence: ");
    printf("%d ", head);
    for(int i = 0; i < req_num; i++){
    
    
        int req_id = request[dis_idx[i]];
        printf("%d ", req_id);
        cylinders[req_id]--;
        move_sum += abs(head - req_id);
        head = req_id;
    }
    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));

}

Code description:

According to the principle of the SSTF algorithm, the request closest to the magnetic head needs to be processed first, so the distance between the magnetic head and the request is sorted from small to large by using bubble sorting. The distance is recorded in dis_list, and the subscript of the corresponding request is recorded in dis_idx, which is convenient. Fetch the requested number of tracks after the sort.

Experimental results :

the queue with requests for cylinders: 98 183 37 122 14 124 65 67

the head's position of cylinder: 53

image-20220613173745498

In the SSTF scheduling strategy, input 8 track request sequences, specify the initial position of the magnetic head as 53, and finally obtain the average moving distance of the magnetic head as 236, and the average response time as 29;

Compared with the FCFS scheduling strategy, the average moving total distance and average response time of SSTF are better;

3. SCAN

For the scan algorithm, the arm starts at one end of the disk and moves toward the other; requests are processed as it moves across each cylinder. When the other end of the disk is reached, the direction of head movement is reversed, and processing continues. The head continuously scans the disk back and forth. The SCAN algorithm is sometimes called the elevator algorithm because the head behaves like an elevator in a building, processing all upward requests before processing requests in the opposite direction.

image-20220612203024819

Implementation code:

void SCAN(int head, int *request, int *cylinders, int req_num, int dir){
    
    
    if(dir != 1 && dir != 0){
    
    
        printf("Direction Error\n");
        return;
    }
    printf("===============SCAN=============\n");
    int move_sum = 0;
    int dis_list[req_num];
    int dis_idx[req_num];
    int pre_head = head;
    for(int i = 0; i < req_num; i++){
    
    
        int dis = abs(head - request[i]);
        dis_list[i] = dis;
        dis_idx[i] = i;
    }
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
    printf("Head location: %d\n", head);

    printf("Head moving sequence: ");
    printf("%d ", head);
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        if(dir == 0) head--;
        else head++; 
    }
    if(head == -1) head++;
    else if(head == CYLINDER_MAX) head--;

    //移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动
    if(pre_head != head){
    
    
        printf("%d ", head);
        move_sum += abs(pre_head - head);
        pre_head = head;
    }
   
    if(dir == 1) dir = 0;
    else dir = 1;
  
		//反向移动磁头
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        if(dir == 0) head--;
        else head++; 
    }

    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));

}

Code description:

According to the principle of the SCAN scheduling algorithm, the head is moved in the specified direction through the while loop, and the request is processed until it reaches the end of the recorded track, and then the direction of the head is reversed to continue moving the head, also through the while loop. accomplish;

Experimental results:

Head location: 100

Head moving sequence: 55 58 39 18 90 160 150 38 184

Head moving direction: right

image-20220613195948429

In the SCAN scheduling strategy, input 9 track request sequences, specify the initial position of the magnetic head as 100, and move the magnetic head to the right (the direction in which the track number increases). Finally, the average total moving distance of the magnetic head is 280, and the average response time is 31;

Compared with FCFS and SSTF scheduling strategies, SCAN has better average moving distance and average response time;

4. C-LOOK

Based on the SCAN algorithm, C-LOOK moves the magnetic head from one end of the disk to the other end of the disk (the magnetic arm only needs to move to the farthest request in one direction), and processes the request on the trip, however, when the magnetic head reaches the other end, it immediately Go back to the farthest request on the other side of the disk without processing any requests on the backhaul, and then continue moving the disk in the same direction to process requests from that farthest request.

image-20220612203236118

Implementation code:

void C_LOOK(int head, int *request, int *cylinders, int req_num, int dir){
    
    
      if(dir != 1 && dir != 0){
    
    
        printf("Direction Error\n");
        return;
    }
    printf("===============C-LOOK=============\n");
    int move_sum = 0;
    int pre_head = head;
    int left = 0, right = 0;//记录最远两端的请求
    int flag = 0;
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
  
  	//获取最远两端的请求left和right
    for(int i = 0; i < CYLINDER_MAX; i++){
    
    
        if(cylinders[i] && !flag) {
    
    
            left = i;
            flag = 1;
        }
        if(flag && cylinders[i]){
    
    
            right = i;
        }
    }
  
    printf("Left Bound: %d, Right Bound: %d\n", left, right);
    printf("Head location: %d\n", head);

    printf("Head moving sequence: ");
    printf("%d ", head);
  
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        //当磁头到达最远端的请求
        if(head == right && dir){
    
     
            cylinders[head]--;
            break;
        }
        if(head == left && !dir) {
    
    
            cylinders[head]--;
            break;
        }

        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        //磁头按指定方向移动
        if(dir == 0) head--;
        else head++; 
    }
    
    // 移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动
    if(pre_head != head){
    
    
        printf("%d ", head);
        move_sum += abs(pre_head - head);
        pre_head = head;
    }

    //直接移动到另一端最远的请求,过程中不处理请求
    if(dir == 1){
    
    
        head = left;
        cylinders[head]--;
    }
    else{
    
    
        head = right;
        cylinders[head]--;
    }
		printf("%d ", head);
    move_sum += abs(pre_head - head);
    pre_head = head;

    //磁头继续沿着最初指定的方向移动
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        if(dir == 0) head--;
        else head++; 
    }

    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));
}

Code description:

According to the principle of the C-LOOK scheduling algorithm, first record the requests at the farthest ends, save them in the variables left and right, and then use the while loop to move the head in the specified direction in the track, and process the requests until it reaches the record The farthest request (depending on the direction of movement), and then move the head to the farthest request at the other end, and continue to move the head in the originally specified direction from this request, which is also achieved through a while loop;

Experimental results:

Head location: 100

Head moving sequence: 55 58 39 18 90 160 150 38 184

Head moving direction: right

image-20220614200010799

In the C-LOOK scheduling strategy, input 9 track request sequences, specify the initial position of the magnetic head as 100, and move the magnetic head to the right (the direction in which the track number increases). Finally, the average moving distance of the magnetic head is 322, and the average response time is 35 ;

Compared with FCFS and SSTF scheduling strategies, the average total moving distance and average response time of C-LOOK are better than FCFS and SSTF, but worse than SCAN scheduling strategy;

The input sequence of cylinder requests has a local distribution:

Head location: 25

Head moving sequence: 20 30 12 20 30 12 20 30 12 30

Head moving direction: right

请求序列工作集 = {12, 20, 30}

image-20220615145325660

It can be seen from the results that C-LOOK has the best performance and SCAN has the worst performance. From an intuitive point of view, since the sequence of requests is concentrated at 12, 20, and 30, the SCAN scheduling algorithm needs to move the head to the end of the track every time. , which leads to a larger moving distance than the other three algorithms; and in C-LOOK, the head moves to the farthest request of the request sequence and stops, and after processing all the requests of the track, it moves to other requests. Therefore, the moving distance of the magnetic head is greatly reduced; the performance of SSTF is also relatively good;

Head location: 50

Head moving sequence: 10 100 5 10 100 5 10 100 5 10 100 5

Head moving direction: right

请求序列工作集 = {5, 10, 100}

image-20220615145443539

In this cylinder request sequence with locality, the working set is {5, 10, 100}, and it can be seen that the distance between requests 5 and 100 is relatively large;

Among the four head scheduling algorithms, SSTF has the best performance, because when the distance between requests is relatively long, SSTF always selects the request closest to the current head for processing, thus avoiding long-distance movement and improving performance. ;

It can be seen that the performance of FCFS is the worst. Intuitively speaking, because the requests of tracks 100 and 5 in the request sequence always appear adjacent to each other, and their distance is relatively large, the moving distance of the head is greatly increased;

II. Comparison of FCFS, SSTF, SCAN and C-LOOK Scheduling Strategies

The advantages and disadvantages of the four head scheduling algorithms are summarized in the table below:

advantage shortcoming
FCFS fair and simple The average seek distance is large, and it is only used in occasions with less disk I/O
SSTF Better performance than FCFS Can not guarantee the shortest average seek time (TSP problem), prone to "starvation" phenomenon
SCAN Better seek performance, can avoid "starvation" phenomenon Not conducive to access requests away from the end of the head
C-LOOK Eliminates unfairness of requests for tracks at both ends ------------------------------------------------------------

Full code:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<math.h>
#define CYLINDER_MAX 200 //最大磁道数
#define REQUEST_MAX 20  //最大请求数
 
 
//设置磁道请求
void set_request(int *cylinders, int *request, int req_num){
    
    
    for(int i = 0; i < req_num; i++){
    
    
        int req_id = request[i];
        cylinders[req_id]++; //对应的磁道请求数加1
    }
}

void FCFS(int head, int *request, int *cylinders, int req_num){
    
    
    printf("===============FCFS=============\n");
    int move_sum = 0;
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
    printf("Head location: %d\n", head);
    printf("Processing sequence: ");
    printf("%d ", head);
    for(int i = 0; i < req_num; i++){
    
    
        int req_id = request[i];
        printf("%d ", req_id);
        cylinders[req_id]--;
        move_sum += abs(head - req_id);
        head = req_id;
    }
    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));


}

void SSTF(int head, int *request, int *cylinders, int req_num){
    
    
    printf("===============SSTF=============\n");
    int move_sum = 0;
    int dis_list[req_num];
    int dis_idx[req_num];
    int init_head = head;
    for(int i = 0; i < req_num; i++){
    
    
        int dis = abs(head - request[i]);
        dis_list[i] = dis;
        dis_idx[i] = i;
    }
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
    printf("Head location: %d\n", head);
    //对dis_list从小到大进行排序,作为磁道请求序列
    for(int i = 0; i < req_num - 1; i++){
    
    
        for(int j = 0; j < req_num - i - 1; j++){
    
    
            if(dis_list[j] > dis_list[j+1]){
    
    
                int temp = dis_list[j];
                int temp_idx = dis_idx[j];
                dis_list[j] = dis_list[j+1];
                dis_idx[j] = dis_idx[j+1];
                dis_list[j+1] = temp;
                dis_idx[j+1] = temp_idx;
            } 
        }
    }
    printf("Processing sequence: ");
    printf("%d ", head);
    for(int i = 0; i < req_num; i++){
    
    
        int req_id = request[dis_idx[i]];
        printf("%d ", req_id);
        cylinders[req_id]--;
        move_sum += abs(head - req_id);
        head = req_id;
    }
    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));

}

void SCAN(int head, int *request, int *cylinders, int req_num, int dir){
    
    
    if(dir != 1 && dir != 0){
    
    
        printf("Direction Error\n");
        return;
    }
    printf("===============SCAN=============\n");
    int move_sum = 0;
    int pre_head = head;
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
    printf("Head location: %d\n", head);

    printf("Head moving sequence: ");
    printf("%d ", head);
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        if(dir == 0) head--;
        else head++; 
    }
    if(head == -1) head++;
    else if(head == CYLINDER_MAX) head--;

    // 移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动
    if(pre_head != head){
    
    
        printf("%d ", head);
        move_sum += abs(pre_head - head);
        pre_head = head;
    }
   
    if(dir == 1) dir = 0;
    else dir = 1;

    while(head >= 0 && head < CYLINDER_MAX){
    
    
        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        if(dir == 0) head--;
        else head++; 
    }

    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));

}


void C_LOOK(int head, int *request, int *cylinders, int req_num, int dir){
    
    
      if(dir != 1 && dir != 0){
    
    
        printf("Direction Error\n");
        return;
    }
    printf("===============C-LOOK=============\n");
    int move_sum = 0;
    int pre_head = head;
    int left = 0, right = 0;
    int flag = 0;
    memset(cylinders, 0, CYLINDER_MAX * sizeof(int));
    set_request(cylinders, request, req_num);
    for(int i = 0; i < CYLINDER_MAX; i++){
    
    
        if(cylinders[i] && !flag) {
    
    
            left = i;
            flag = 1;
        }
        if(flag && cylinders[i]){
    
    
            right = i;
        }
    }
    printf("Left Bound: %d, Right Bound: %d\n", left, right);
    printf("Head location: %d\n", head);

    printf("Head moving sequence: ");
    printf("%d ", head);
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        //当磁头到达最远端的请求
        if(head == right && dir){
    
     
            cylinders[head]--;
            break;
        }
        if(head == left && !dir) {
    
    
            cylinders[head]--;
            break;
        }

        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        //磁头按指定方向移动
        if(dir == 0) head--;
        else head++; 
    }
    
    // 移动到磁道尽头后, pre_head修改为head的位置,以便磁头换方向移动
    if(pre_head != head){
    
    
        printf("%d ", head);
        move_sum += abs(pre_head - head);
        pre_head = head;
    }

    //直接移动到另一端最远的请求,过程中不处理请求
    if(dir == 1){
    
    
        head = left;
        cylinders[head]--;
        
    }
    else{
    
    
        head = right;
        cylinders[head]--;
    }
    printf("%d ", head);
    move_sum += abs(pre_head - head);
    pre_head = head;

    //磁头继续沿着指定方向移动
    while(head >= 0 && head < CYLINDER_MAX){
    
    
        while(cylinders[head] > 0){
    
    
            printf("%d ", head);
            move_sum += abs(pre_head - head);
            pre_head = head;
            cylinders[head]--;
        }

        if(dir == 0) head--;
        else head++; 
    }

    printf("\nAverage total distance of head movement = %d\n", move_sum);
    printf("Average average response time = %f\n\n", (double)(move_sum/req_num));

}


int main(){
    
    
    int request[REQUEST_MAX];
    int cylinders[CYLINDER_MAX];
    int N, head, dir;
    printf("Please enter the number of requests for cylinders: ");
    scanf("%d", &N);
    printf("Please enter the queue with requests for cylinders: ");
    for(int i =0 ; i < N; i++){
    
    
        scanf("%d", &request[i]);
    }

    printf("Please input the head's position of cylinder: ");
    scanf("%d", &head);

    printf("Please enter the moving direction of the head (0: left, 1: right): ");
    scanf("%d", &dir);
    printf("\n");

    FCFS(head, request, cylinders, N);
    SSTF(head, request, cylinders, N);
    SCAN(head, request, cylinders, N, dir);
    C_LOOK(head, request, cylinders, N, dir);

}

Guess you like

Origin blog.csdn.net/m0_52387305/article/details/125297809