《操作系统30天》-合川秀实-学习日志day13

一、简化字符串显示

将类似于这种三步操作:
1)涂上背景色
2)在上面写字符
3)完成刷新
在这里插入图片描述
放到一个函数中,如果需要显示字符就直接调用封装好的函数,各个参数代表的含义
在这里插入图片描述
在这里插入图片描述
这样原来的三行代码就可以简化成(只要需要输出字符,就可以用这个函数替换)
在这里插入图片描述

二、重新调整FIFO缓冲区

把定时器用的多个FIFO缓冲区集中成一个,在集装的FIFO中用不同的数据来分辨出是哪个定时器超时。
主函数内的修改:
在这里插入图片描述
对if语句的修改:
在这里插入图片描述
测试性能:
在进入循环的时候添加count++,完全不显示计数,到了10秒后超时的时候再显示这个count值,在启动3秒的时候把count复位为0。==这里的原理是用定时器计时到10秒输出循环的次数,但是每次要做中断处理(鼠标键盘)都会占用时间,那么循环的次数就会因此变小,越小说明处理的时间越长,==这不是我们想要的。因为我们做的这个操作系统启动(初始化)的时候只要有些条件发生了变化,电脑花费的时间就会不稳定,这就导致开始的时间存在误差,所以统一在3秒后复位,保证时间统一开始。
动了一圈鼠标的效果:
在这里插入图片描述
没有动鼠标的效果:
在这里插入图片描述
可以发现以上两个结果的count值是不一样的,区别只在于动没动鼠标,我们再用harib10d,harib10e,harib10f…分别测试一下不动鼠标的结果:
在这里插入图片描述
根据以上趋势,每次优化之后count的值会变大,count的值越大说明每次的性能变好。
根据定时器可以归纳到一个FIFO缓存区的思想,同理,键盘和鼠标也可以归纳到一个FIFO缓冲区来管理:
if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) + fifo8_status(&timerfifo) == 0)
用写入FIFO的数值来判断中断类型:
在这里插入图片描述
没有修改之前的FIFO参数类型为Char,最大只能达到256,对鼠标这种767的数值就不能指定,所以要修改FIFO中的参数类型(修改为int型以前的8位变成32位):
在这里插入图片描述
初始化修改(实际上只修改了函数名和参数类型buf):

void fifo32_init(struct FIFO32 *fifo, int size, int *buf) 	-> FIFO缓冲区的初始化
int fifo32_put(struct FIFO32 *fifo, int data)		-> 给FIFO发生数据并储存在FIFO中
int fifo32_get(struct FIFO32 *fifo) 	-> 从FIFO取得一个数据
int fifo32_status(struct FIFO32 *fifo)		->报告已经存储了多少数据

对keyboard.c和mouse.c中的鼠标和键盘的程序也要做修改:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
修改定时器结构体:
在这里插入图片描述
Timer.c:

void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data)
void inthandler20(int *esp)
{
	……
for (i = 0; i < timerctl.using; i++) {
/*因为 timers的定时器都处于运行状态,所以不确定flags */
		if (timerctl.timers[i]->timeout > timerctl.count) {
			break;
		}
		/* 超时*/
		timerctl.timers[i]->flags = TIMER_FLAGS_ALLOC;
		fifo32_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data);
	}
	timerctl.using -= i;
	…….
}

最后修改HariMain:

Char s[40]
int fifobuf[128];
(中略)
		fifo32_init(&fifo, 128, fifobuf);
	init_pit();
	init_keyboard(&fifo, 256);
	enable_mouse(&fifo, 512, &mdec);
	io_out8(PIC0_IMR, 0xf8); /* 设定PIT和PIC1以及键盘为许可(11111000) */
	io_out8(PIC1_IMR, 0xef); /* 设定鼠标为许可(11101111) */

	timer = timer_alloc();
	timer_init(timer, &fifo, 10);
	timer_settime(timer, 1000);
	timer2 = timer_alloc();
	timer_init(timer2, &fifo, 3);
	timer_settime(timer2, 300);
	timer3 = timer_alloc();
	timer_init(timer3, &fifo, 1);
		timer_settime(timer3, 50);
for (;;) {
		count++;
		io_cli();
		if (fifo32_status(&fifo) == 0) {
			io_sti();
		} else {
			i = fifo32_get(&fifo);
			io_sti();
			if (256 <= i && i <= 511) { /*键盘数据 */
				sprintf(s, "%02X", i - 256);
		putfonts8_asc_sht(sht_back, 0, 16, COL8_FFFFFF, COL8_008484, s, 2);
			} else if (512 <= i && i <= 767) { /* 鼠标数据 */
				if (mouse_decode(&mdec, i - 512) != 0) {
					/* 已经收集了3字节的数据,所以显示出来 */
					sprintf(s, "[lcr %4d %4d]", mdec.x, mdec.y);
					if ((mdec.btn & 0x01) != 0) {
						s[1] = 'L';
					}
					if ((mdec.btn & 0x02) != 0) {
						s[3] = 'R';
					}
					if ((mdec.btn & 0x04) != 0) {
						s[2] = 'C';
					}
		putfonts8_asc_sht(sht_back, 32, 16, COL8_FFFFFF, COL8_008484, s, 15);
					/* 鼠标指针的移动 */
					mx += mdec.x;
					my += mdec.y;
					if (mx < 0) {
						mx = 0;
					}
					if (my < 0) {
						my = 0;
					}
					if (mx > binfo->scrnx - 1) {
						mx = binfo->scrnx - 1;
					}
					if (my > binfo->scrny - 1) {
						my = binfo->scrny - 1;
					}
					sprintf(s, "(%3d, %3d)", mx, my);
	putfonts8_asc_sht(sht_back, 0, 0, COL8_FFFFFF, COL8_008484, s, 10);
					sheet_slide(sht_mouse, mx, my);
				}
			} else if (i == 10) { /* 10秒定时器 */
	putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
				sprintf(s, "%010d", count);
	putfonts8_asc_sht(sht_win, 40, 28, COL8_000000, COL8_C6C6C6, s, 10);
			} else if (i == 3) { /* 3秒定时器 */
		putfonts8_asc_sht(sht_back, 0, 80, COL8_FFFFFF, COL8_008484, "3[sec]", 6);
				count = 0; /* 开始测试 */
			} else if (i == 1) { /* 光标用定时器 */
				timer_init(timer3, &fifo, 0); /* 下面是设定0 */
				boxfill8(buf_back, binfo->scrnx, COL8_FFFFFF, 8, 96, 15, 111);
				timer_settime(timer3, 50);
				sheet_refresh(sht_back, 8, 96, 16, 112);
			} else if (i == 0) { /* 光标用定时器 */
				timer_init(timer3, &fifo, 1); /* 下面是设定1 */
				boxfill8(buf_back, binfo->scrnx, COL8_008484, 8, 96, 15, 111);
				timer_settime(timer3, 50);
				sheet_refresh(sht_back, 8, 96, 16, 112);
			}
		}
	}

优化完成之后与之前的对比:
Harib10c:
在这里插入图片描述
harib10g:
在这里插入图片描述
效果明显,优化达到1.85倍左右,作者在真机上测试也得到了改善的效果。这次的改善定时器处理还是一样的原理,但是在主函数里我们修改了只查询一个缓冲区,在没有修改之前我们要多次进行查询,所以这次要加速完成查询,使得“count++”在相同的时间内,执行的次数更多。

三、加快中断处理

  • 继续上次没有完成的工作,优化移位处理,定时器的settime是在中断禁止期间进行的,必须要快速完成,如果用移位操作处理多任务(多定时器)的话,时间代价会很高。在FIFO中类此处理方法是:读一个数据之后,改变下一次读数据的地址。不过这个方法不适用于定时器,因为用settime加入中断时,后面的中断必须后移,在中断禁止的情况下,有可能会让下一次读取的定时器发生错误。
  • 笔者用链表的方法让每个定时器都保存下一个定时器的地址:
    在这里插入图片描述
    在这里插入图片描述
    修改定时器的中断处理程序(只改写timers[0]):
    在这里插入图片描述
    在这里插入图片描述
    修改timer_settime函数:
void timer_settime(struct TIMER *timer, unsigned int timeout)
{
	int e;
	struct TIMER *t, *s;
	timer->timeout = timeout + timerctl.count;
	timer->flags = TIMER_FLAGS_USING;
	e = io_load_eflags();
	io_cli();
	timerctl.using++;
	if (timerctl.using == 1) {
		/* 处于运行状态的定时器只有这一个时 */
		timerctl.t0 = timer;
		timer->next = 0; /*没有下一个 */
		timerctl.next = timer->timeout;/*下一次的定时器是这个*/
		io_store_eflags(e);
		return;
	}
	t = timerctl.t0;
	if (timer->timeout <= t->timeout) {
		/* 插入最前面的情况下 */
		timerctl.t0 = timer;
		timer->next = t; /* 下面是t */
		timerctl.next = timer->timeout;/* 下一次的定时器是这个*/
		io_store_eflags(e);
		return;
	}
	/* 寻找插入位置 */
	for (;;) {
		s = t;
		t = t->next;
		if (t == 0) {
			break; /* 最后面 */
		}
		if (timer->timeout <= t->timeout) {
			/* 插入到s和t之间的时间 */
			s->next = timer; /* s的下一个是timer */
			timer->next = t; /* timer的下一个是t */
			io_store_eflags(e);
			return;
		}

找到位置后:
在这里插入图片描述
在这里插入图片描述

}
	/* 插入最后面的情况下 */
	s->next = timer;
	timer->next = 0;
	io_store_eflags(e);
	return;
}

使用链表的结构之后,timers[]数组已经不需要了,可以直接把最前面的timers[0]定义为t0保留:
在这里插入图片描述
在inthandler20和timer_settime中改写timer[0]为t0。

  • 使用哨兵简化程序
    上面的优化去除了移位处理,但是settime函数还是很长(包含了4种可能实际上可以说成3种因为最后两种的情况可以是一样的):
    在这里插入图片描述
    这次优化减少了四种情况发生的可能,相当于在最大时间处设定了一个定时器称之为“哨兵”,因为无论如何都不可能到达这个时刻0xffffffff:
    在这里插入图片描述
    如果使用需要调整的程序(一年调整一次)必须保证不改变哨兵时刻,哨兵的时刻调整:
    在这里插入图片描述
    加入哨兵之后4种情况变成两种(1,4都不会发生):
    在这里插入图片描述
    修改settime:
    在这里插入图片描述
    精简inthandler20函数:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    到了这一步,using就用了,我们可以用哨兵来判断有没有定时器在使用,最后精简inthandler20函数:
    在这里插入图片描述
    最后的效果:
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值