仓促发一些资料,既当备份又当分享,有时间再考虑仔细补充和调整(主要是一些试验用的代码和注释没去掉,但功能不影响)
根据e4rat获取的列表用python脚本生成squashfs的sort文件(参考:
https://unix.stackexchange.com/a/474826/259284)
被排序后的squashfs启动速度大约14秒左右,相比把e4rat获取的列表单独创建一个squashfs与overlayfs结合,这种方式boot速度稍快一些,也不像套两层squashfs会出现
莫名其妙的问题
代码: 全选
#!/bin/python3
import random
random_priorities=list(range(-32768,32768))
random_priorities_len=len(random_priorities)
random_priorities=random.sample(random_priorities,random_priorities_len)
priority=32767
i=0
try:
while priority>=-32768:
x=input().lstrip('./')
entry=x.strip()+' '+str(priority-i)
print(entry)
i+=1
except EOFError:
pass
一个针对squashfs改编的e4rat-preload-lite.c(从
这个文件改编)
inode 排序在squashfs已经排序的情况下没有意义,所以去掉了.
不过我的用法是在initramfs里root目录挂载之后立即用chroot运行这个程序在后台(chroot "${rootmnt}" /sbin/e4rat-preload-lite &),这样启动init进程和预读是并行进行的.
使用这个程序预读的目的主要是加速进入桌面后的各种操作.
被排序处理过得squashfs配合1M的数据块本身就在boot上有很好的表现,预读本身可能会对boot造成很小的负面影响(能力有限,测不出具体多少,总之很小,难以测量)
代码: 全选
// Maintained by Simonas Kazlauskas, 2012.
//
// Original version written by John Lindgren11, 2011.
// It can be found on http://e4rat-l.bananarocker.org/
//
// Replacement for e4rat-preload, which was written by Andreas Rid, 2011.
#define _GNU_SOURCE
#define _DEFAULT_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define VERBOSE 0
#define LIST "/var/lib/e4rat/startup.log"
#define INIT "/bin/systemd"
#define MAX_EARLY 0
#define BLOCK 65536
#define BUF 1048576 // = 1 MiB
typedef struct {
int dev;
uint64_t inode;
char *path;
} FileDesc;
static FileDesc **list = NULL;
//static FileDesc **sorted = NULL;
static int listlen = 0;
#ifndef strdup
char *strdup(const char *source);
#endif
//~ static int sort_cb(const void *_a, const void *_b){
//~ // qsort helper for file list entries. Sorts by device and inode.
//~ FileDesc *a = *(FileDesc **)_a;
//~ FileDesc *b = *(FileDesc **)_b;
//~ if(a->dev < b->dev){
//~ return -1;
//~ }
//~ if(a->dev > b->dev){
//~ return 1;
//~ }
//~ if(a->inode < b->inode){
//~ return -1;
//~ }
//~ if(a->inode > b->inode){
//~ return 1;
//~ }
//~ return 0;
//~ }
static void die(const char *msg){
printf("Error: %s.\n", msg);
exit(EXIT_FAILURE);
}
static void free_list(FileDesc **list){
for (int i = 0; i < listlen; i++) {
free(list[i]->path);
free(list[i]);
}
free(list);
list = NULL;
}
static FileDesc *parse_line(const char *line){
// Parses a line from the file list. Returns NULL in case of parse errors.
// Expected format of the line:
// (device) (inode) (path)
// Example:
// 2049 2223875 /bin/bash
int dev = 0;
//~ while(*line >= '0' && *line <= '9'){
//~ dev = dev * 10 + (*line++ - '0');
//~ }
//~ if(*line++ != ' '){
//~ return NULL;
//~ }
uint64_t inode = 0;
//~ while(*line >= '0' && *line <= '9'){
//~ inode = inode * 10 + ((*line++) - '0');
//~ }
//~ if(*line++ != ' '){
//~ return NULL;
//~ }
FileDesc *f = malloc(sizeof(FileDesc));
if(!f) die("Failed to allocate memory while parsing file list!");
f->dev = dev;
f->inode = inode;
f->path = strdup(line);
if(!f->path) die("Failed to allocate memory for file path");
return f;
}
static void load_list(void){
// Loads list and parses contents into FileDescs
#if VERBOSE > 0
printf("Loading %s.\n", LIST);
#endif
FILE *stream = fopen(LIST, "r");
if (!stream) die(strerror(errno));
int listsize = 0;
char buf[4096];
while(1){
if(!fgets(buf, sizeof buf, stream)){
break;
}
if(buf[0] && buf[strlen(buf) - 1] == '\n'){
buf[strlen (buf) - 1] = 0;
}
FileDesc *f = parse_line(buf);
if(!f){
continue;
}
if(listlen >= listsize){
listsize = listsize ? listsize * 2 : 256;
list = realloc(list, sizeof(FileDesc *) * listsize);
}
list[listlen++] = f;
}
fclose(stream);
list = realloc(list, sizeof(FileDesc *) * listlen);
if(!list) die("Could not allocate memory for lists");
//~ sorted = malloc(sizeof(FileDesc *) * listlen);
//~ if(!list || !sorted) die("Could not allocate memory for lists");
//~ memcpy(sorted, list, sizeof(FileDesc *) * listlen);
//~ qsort(sorted, listlen, sizeof(FileDesc *), sort_cb);
}
static void load_inodes(const int a, const int b){
//~ struct stat s;
//~ for(int i = a; i < ((b < listlen) ? b : listlen); i++){
//~ stat(sorted[i]->path, &s);
//~ }
struct stat s;
for(int i = a; i < b && i < listlen; i ++){
stat(list[i]->path, &s);
}
}
static void exec_init(char **argv){
#if VERBOSE > 0
printf("Executing %s.\n", INIT);
#endif
switch(fork()){
case -1:
die(strerror(errno));
case 0:
return;
default:
execv(INIT, argv);
die(strerror(errno));
}
}
static void load_files(int a, int b){
void *buf = malloc(BUF);
if(!buf) die("Failed to allocate preload buffer");
for(int i = a; i < b && i < listlen; i ++){
int handle = open(list[i]->path, O_RDONLY);
if(handle < 0){
continue;
}
//readahead(handle,0,~0UL);
while(read(handle, buf, BUF) > 0){}
close(handle);
}
free(buf);
}
static void load_all(int a, int b){
struct stat s;
void *buf = malloc(BUF);
if(!buf) die("Failed to allocate preload buffer");
for(int i = a; i < b && i < listlen; i ++){
stat(list[i]->path, &s);
int handle = open(list[i]->path, O_RDONLY);
if(handle < 0){
continue;
}
//readahead(handle,0,~0UL);
while(read(handle, buf, BUF) > 0){}
close(handle);
}
free(buf);
}
int main(int argc, char **argv){
int early_load = 0;
load_list();
#if VERBOSE > 0
printf("Preloading %d files.\n", listlen);
#endif
//early_load = listlen * 0.33;
//if(early_load > MAX_EARLY) early_load = MAX_EARLY;
early_load = MAX_EARLY;
// Preload a third of the list or MAX_EARLY files (whichever is smaller),
// then start init.
load_inodes(0, early_load);
load_files(0, early_load);
//~ load_all(0, early_load);
if (getpid()==(pid_t)(1)){exec_init(argv);}
// And continue preloading files further in chunks of BLOCK files.
for(int i = early_load; i < listlen; i += BLOCK){
load_inodes(i, i + BLOCK);
load_files(i, i + BLOCK);
//~ load_all(i, i + BLOCK);
}
free_list(list);
// As sorted originally was a copy of list, it's contents are already
// freed by the time we are freeing sorted list
//free(sorted);
exit(EXIT_SUCCESS);
}