模式 01: 内核中常见的性能优化方法 2017-02-23

1. 批量处理

add_to_page_cache_lru, 操作lru的话, 先放到per cpu的lru cache (struct pagevec), 待lru cache存满后drain.

2. 吞吐量(Throughput)和时延(Latency)

2.1 HZ 设置为 250, 1000等.

2.2 中断线程化后, 吞吐量可能下降, 但系统其它地方的时延可能改善.

3. 用空间换时间

计算结果缓存之类的, 比如 一些数值计算, 开根号什么的.

4. 收敛?

radix tree的tag, 不必逐个判断该节点 子树 下的叶子. 这个可能也可以归到 缓存 中.

hash应该也算这个类别.

内核中 通过 struct pt_regs 来获取 用户传递的参数 2017-02-23

基于 linux-2.6.35.7/drivers/char/mem.c

#include <asm/ptrace.h>
#include <asm/uaccess.h>

static ssize_t kmsg_write(struct file *file, const char __user *buf,
              size_t count, loff_t *ppos)
{
    char *tmp;
    ssize_t ret;

    tmp = kmalloc(count + 1, GFP_KERNEL);
    if (tmp == NULL)
        return -ENOMEM;
    ret = -EFAULT;
    if (!copy_from_user(tmp, buf, count)) {
        tmp[count] = 0;
        //add
        #define STR_FOUND "sth_will_show_in_dmesg"
        if(NULL!=strstr(tmp,STR_FOUND))
        {
            struct pt_regs *usr_regs; 
            usr_regs=task_pt_regs(current); 
            if(valid_user_regs(usr_regs))
            {
                int fd=usr_regs->ARM_r0;
                char *write_buf=usr_regs->ARM_r1;
                int len=usr_regs->ARM_r2;
                /*用户态程序:
                #define STR_TMP "sth_will_show_in_dmesg"
                int fd=open("/dev/kmsg", O_WRONLY);
                write(fd,STR_TMP,strlen(STR_TMP));
                */

                /*
                内核打印:
                kmsg_write(),969:3 0x6fee0 22
                kmsg_write(),971:buf:sth_will_show_in_dmesg
                也就是打印出了 用户态传递的参数
                */
                tmp_print("%d 0x%x %d",fd,write_buf,len);
                if(access_ok(VERIFY_READ, (void *) write_buf,strlen(write_buf)))
                    tmp_print("buf:%s\n",write_buf);
            }
            else
            {
                tmp_print("not valid_user_regs\n");
            }


        }
        //end add
        ret = printk("%s", tmp);
        if (ret > count)
            /* printk can add a prefix */
            ret = count;
    }
    kfree(tmp);
    return ret;
}

IIC相关内容的记忆 2017-02-15

本文的内容 仅仅是为了能够回想起IIC相关内容, 并不求严谨和准确.

1. 起始和停止信号

因为上拉省电, 所以, 空闲时, SDA是上拉的. 在时钟为高时, SDA若表示数据, 需维持稳定, 否则, 其表示起始或停止.

2. 数据的组织 和 表示

假定是7bit地址的情况. 先发送高位还是低位?
可以考虑/回忆下 7bit地址+1bit读写 时的情况, 我们是先发送地址的, 所以, 是先发送高位, 后发送低位的.

最常见的是r/w# 所以,读为1, 写为0.

时钟有, 代表心脏还在跳, 器件还在工作, 所以, 在SCL高电平时对SDA采样作为数据.

page reclaim 00:相关资料 2017-02-07

  1. [Professional Linux Kernel Architecture]

  2. Reducing Memory Access Latency by Satoru Moriya http://events.linuxfoundation.org/sites/events/files/lcjp13_moriya.pdf

  3. https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/

  4. [Understanding the Linux Kernel, 3rd Edition]

page reclaim 01:概述 2017-02-07

1. 背景/问题引入

本文不讨论 swapping (swap out to disk).

If a seldom-used page is backed by a block device (e.g., memory mappings of files) then the modified pages need not be swapped out, but can be directly synchronized with the block device. The page frame can be reused, and if the data are required again, it can be reconstructed from the source. If a page is backed by a file but cannot be modified in memory (e.g., binary executable data), then it can be discarded if it is currently not required. 通过Writing back cached data即可将这些page释放.

If a page is backed by a file but cannot be modified in memory (e.g., binary executable data), then it can be discarded if it is currently not required.

将 暂时不用的 或 很少使用的 内存回笼/回收, 给后续其他人使用. 那么, 如何界定 暂时不用 或 很少使用 呢? 这些已分配出去的内存都散落在哪里?

2. 散落在哪

如何找到这些内存呢? 啥链表吗?
答:see addtopagecachelru(), pageaddnewanonrmap()

方式1: addtopagecachelru 把page添加到 both the page cache and the LRU cache. Most importantly, it is used by mpagereadpages and dogenericmappingread, the standard functions in which the block layer ends up when reading data from a file or mapping. 当然, 实际是先添加到per cpu的struct pagevec中, 等满了再转移到global的lru中.