跳转至

2023

Make

简介

make 和 makefile 是 Linux 系统下 C/C++ 工程的编译工具,它们用来自动化配置实验环境,编译项目文件。makefile 文件描述了项目文件之间的依赖关系和编译规则,make 命令根据 makefile 文件的内容执行编译任务123。相对于 cmake 等其他的编译工具,make 和 makefile 有以下几个特点:

  • make 和 makefile 是 GNU 的标准工具,可以在多种平台上使用。
  • make 和 makefile 可以根据文件时间戳自动发现更新过的文件而减少编译的工作量。
  • make 和 makefile 可以灵活地定义变量、函数和条件判断等,实现复杂的编译逻辑

对于复杂的项目,能通过makefile文件将

  • 实验环境Build,(提前设置相关路径参数)
  • wget/git 下载相关文件到对应目录
  • apt install
  • 样例测试test,
  • 整体运行/Benchmark运行run,
  • 环境清理clean 统一起来

Makefile 执行流程

  • make的默认目标是makefile中的第一个目标,而其它目标一般是由这个目标连带出来的。

常用命令

# 不实际运行,但是打印会运行的命令
make -f makefile.llvm -n
# -W 假设某个文件是最新的,不需要重新编译。常见结合 -n 使用
make inj -f makefile.llvm -n -W svm.inj

打印debug信息,makefile如何选择决策

  • --debug=v 输出的信息包括哪个makefile被解析,不需要被重编译的依赖文件(或是依赖目标)等。
  • --debug=i implicit,输出使用的隐含规则过程。
  • --debug=m 输出make读取makefile,更新makefile,执行makefile的信息。

Makefile 隐含规则

  • “隐含规则”也就是一种惯例,make会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile中没有书写这样的规则。
  • 例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来,make会自动推导出这种规则,并生成我们需要的[.o]文件。
  • 将头文件变成.gch precompiled headers
  • 许多的隐含规则都是使用了“后缀规则”来定义的
  • 变量.SUFFIXES存储了默认的依赖目标,可以修改。默认的后缀列表是:.out,.a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el
  • 要让make知道一些特定的后缀,我们可以使用伪目标".SUFFIXES"来定义或是删除,如:

  • 把后缀.hack和.win加入后缀列表中的末尾。

SUFFIXES: .hack .win
  1. 先删除默认后缀,后定义自己的后缀列表。
.SUFFIXES: # 删除默认的后缀
.SUFFIXES: .c .o .h # 定义自己的后缀

模式规则

  • 常见使用模式规则来定义一个隐含规则
  • 至少在规则的目标定义中要包含"%"
%.o : %.c ; <command ......>

老式风格的"后缀规则"

  • 后缀规则是一个比较老式的定义隐含规则的方法。
  • 后缀规则会被模式规则逐步地取代。因为模式规则更强更清晰。为了和老版本的Makefile兼容,GNU make同样兼容于这些东西。
  • 后缀规则有两种方式:"双后缀"和"单后缀"。
  • 双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相当于"%o : %c"。
  • 单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% : %.c"。
.cpp.o:
  $(CPPCOMPILE) -c $(COMPILEOPTION) $(INCLUDEDIR) $<

.c.o:
 $(CCOMPILE) -c $(COMPILEOPTION) $(INCLUDEDIR) $<

Makefile编写技巧

Makefile框架

SIM_ROOT ?= $(shell readlink -f "$(CURDIR)") #当前工作目录的绝对路径。
CLEAN=$(findstring clean,$(MAKECMDGOALS)) #???

include common/Makefile.common

$(STANDALONE): $(LIB_CARBON) $(LIB_SIFT) $(LIB_DECODER)
 @$(MAKE) $(MAKE_QUIET) -C $(SIM_ROOT)/standalone #进入standalone目录,执行Makefile文件

Makefile.common文件中的内容如下:

include $(SIM_ROOT)/Makefile.config

DIRECTORIES := ${shell find $(SIM_ROOT)/common -type d -print} #查找common目录下的所有子目录
LIBCARBON_SOURCES = $(foreach dir,$(DIRECTORIES),$(wildcard $(dir)/*.cc)) \
 $(wildcard $(SIM_ROOT)/common/config/*.cpp) # 把变量DIRECTORIES中的每个目录下的所有.cc文件和$(SIM_ROOT)/common/config目录下的所有.cpp文件赋值给变量LIBCARBON_SOURCES

# FLAGS
ifeq ($(SNIPER_TARGET_ARCH),ia32)
  # Add -march=i686 to enable some extra instructions that allow for implementation of 64-bit atomic adds
  CXXFLAGS += -m32 -march=i686 -DTARGET_IA32 # Include paths
  LD_FLAGS += -m32
endif
ifeq ($(SNIPER_TARGET_ARCH),intel64)
  CXXFLAGS += -fPIC -DTARGET_INTEL64
  LD_FLAGS +=
endif

# Build rules for dependency generation
%.d: %.cpp
 $(_MSG) '[DEP   ]' $(subst $(shell readlink -f $(SIM_ROOT))/,,$(shell readlink -f $@)) #把$@的绝对路径中的$(SIM_ROOT)的绝对路径部分替换为空字符串,便于打印
 $(_CMD) $(CXX) -MM -MG $(CPPFLAGS) $(CXXFLAGS) $< | sed -n "H;$$ {g;s@.*:\(.*\)@$*.o $@: \$$\(wildcard\1\)@;p}" >$@
 # 用$(CXX)编译器对$<文件进行依赖分析,并把结果通过sed命令进行处理,然后输出到$@文件

Makefile.config 如下

# 架构判断
ARCH_QUERY=$(shell uname -m)
ifeq ($(ARCH_QUERY),i686)
SNIPER_TARGET_ARCH = ia32
else
ifeq ($(ARCH_QUERY),x86_64)
SNIPER_TARGET_ARCH ?= intel64
#SNIPER_TARGET_ARCH = ia32
else
$(error Unknown target arch: $(ARCH_QUERY))
endif
endif

# 全局的路径
PIN_HOME ?= xxx
PIN_ROOT := $(PIN_HOME)

# 编译器
CC ?= gcc
CXX ?= g++

# DEBUG输出
ifneq ($(DEBUG_SHOW_COMPILE),)  # 如果变量DEBUG_SHOW_COMPILE不为空,如make DEBUG_SHOW_COMPILE=1 使用
  SHOW_COMPILE=1
  MAKE_QUIET=     # 使用情形:$(MAKE) $(MAKE_QUIET) -C pin clean
  _MSG=@echo >/dev/null   # 使用情形:$(_MSG) '[CLEAN ] pin'
  _CMD=       # 使用情形:$(_CMD) git clone --quiet xxx
else
  SHOW_COMPILE=
  MAKE_QUIET=--quiet
  _MSG=@echo
  _CMD=@
endif

打印make的详细信息make DEBUG_SHOW_COMPILE=1 DEBUG=1 -j 16|tee make.log |my_hl

打印make时每项依赖文件的情况

# Sums up number of passes and fails
# cut 命令用于从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。其中 -d (--delimiter)参数指定分隔符(默认TAB),-f (--fields)参数指定要显示的字段。因此,cut -d\  -f 2 的意思是以空格为分隔符,显示第二个字段。
# uniq -c 统计不重复词(PASS\|FAIL)的出现
test-score: test-all
 @$(MAKE) test-all | cut -d\  -f 2 | grep 'PASS\|FAIL' | sort | uniq -c

# Result output strings
PASS = \033[92mPASS\033[0m
FAIL = \033[91mFAIL\033[0m

# Need to be able to build kernels, if this fails rest not run
test-build: all
 @echo " $(PASS) Build"

实现在Makefile里下载

根据是否存在文件来执行makefile语句

ROAD_URL = http://www.dis.uniroma1.it/challenge9/data/USA-road-d/USA-road-d.USA.gr.gz
$(RAW_GRAPH_DIR)/USA-road-d.USA.gr.gz:
 wget -P $(RAW_GRAPH_DIR) $(ROAD_URL)

$(RAW_GRAPH_DIR)/USA-road-d.USA.gr: $(RAW_GRAPH_DIR)/USA-road-d.USA.gr.gz
 cd $(RAW_GRAPH_DIR)
 gunzip < $< > $@

$(GRAPH_DIR)/road.sg: $(RAW_GRAPH_DIR)/USA-road-d.USA.gr converter
 ./converter -f $< -b $@

目录下所有源文件编译成单独的可执行文件

#before run, mkdir build && cd build

CFLAGS = -g -O0

#source files dir
SRC_DIR = ../
#Makefile dir, generally build
BUILD_DIR = ./

#get ../example.c 不能寻找子文件夹的文件,需要shell find
SRCS = $(wildcard $(SRC_DIR)*.c)

#delete .c, then become ../example
# :.c = .o的意思是C文件對應相應的.o文件
FILENAME = $(SRCS:.c=)

#replace src dir with dest dir, then become ./example
PROGS = $(addprefix $(BUILD_DIR),$(notdir $(FILENAME)))

.PHONY: all
all: $(PROGS)
    @echo "-- build all .c files" # makefile中命令前加一个@的作用是不让make显示出要执行的命令
 @echo Building for x86 architecture # echo 无需“”

$(BUILD_DIR)%: $(SRC_DIR)%.c
    gcc $(CFLAGS) -o $@ $<

另一种写法

CC=mpicc
CXX=mpicxx
OPENMP=-fopenmp
SOURCES:=$(shell find $(.) -name '*.c')
SOURCESCXX:=$(shell find $(.) -name '*.cpp')
# SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s)
LIB=-lm
OBJS=$(SOURCES:%.c=%)
OBJS+=$(SOURCESCXX:%.cpp=%)
DEBUG=-g

SRC_DIR_1 = ./Lab1
SRCS_1 = $(shell find $(.) -name '*.c')
FILENAME_1 = $(SRCS_1:.c=)

# lab1 : $(FILENAME_1)
#  @echo $(SRCS_1)
#  @echo "lab1编译完成"
#  if [ ! -d "build" ]; then mkdir build; fi
#  mv $(FILENAME_1) build

all : $(OBJS)
 @echo $(SOURCES) $(SOURCESCXX)
 @echo "编译完成"
 @echo $(OBJS)
 if [ ! -d "build" ]; then mkdir build; fi
 mv $(OBJS) build

%: %.c
 $(CC) $(DEBUG) $(OPENMP) $< $(LIB) -o $@

%: %.cpp
 $(CXX) $(DEBUG) $(OPENMP) $< $(LIB) -o $@

.PHONY: clean showVariable

showVariable:
 @echo $(SOURCES)

clean: 
 rm -rf build

多个文件变一个可执行文件

MPICC = mpicc

LIB = -lm 
C_FLAGS= -O3 -mavx2 -fopenmp $(LIB)

SRC_DIR = src
BUILD_DIR = build/bin
SRCS = $(wildcard $(SRC_DIR)/*.c)
OBJ = $(SRCS:.c=.o)

pivot: ${SRCS}
 echo "compiling $(SRC_DIR) ${FILENAME}"
 $(MPICC) $^ $(C_FLAGS) -o $(BUILD_DIR)/pivot

运行结果

$ make pivot -C ..
make: 进入目录“/home/shaojiemike/github/IPCC2022-preliminary”
echo "compiling src src/Combination src/heapSort src/SunDistance src/MPI src/pivot"
compiling src src/Combination src/heapSort src/SunDistance src/MPI src/pivot
mpicc src/Combination.c src/heapSort.c src/SunDistance.c src/MPI.c src/pivot.c -O3 -mavx2 -fopenmp -lm  -o build/bin/pivot

更复杂

保留.o文件,区分Flag与lib

CC = g++
MPICC = mpicc

C_FLAGS= -O3 -fopenmp 
LIB = -lgomp

INCLUDEPATH = feGRASS
SRC_DIR = feGRASS
BUILD_DIR = build/bin

SRCS = $(wildcard $(SRC_DIR)/*.cpp)
OBJ = $(SRCS:.cpp=.o)
DEBUG_OBJ = $(SRCS:.cpp=_debug.o)
TIME_OBJ = $(SRCS:.cpp=_time.o)
FILENAME = $(SRCS:.cpp=)

.DEFAULT_GOAL := all
all : ${OBJ}
 echo "compiling $(SRC_DIR) ${FILENAME}"
 $(CC) $^ $(LIB) -o $(BUILD_DIR)/main

debugPrint: ${DEBUG_OBJ}
 echo "compiling $(SRC_DIR) ${FILENAME}"
 $(CC) $^ $(LIB) -o $(BUILD_DIR)/main

timePrint: ${TIME_OBJ}
 echo "compiling $(SRC_DIR) ${FILENAME}"
 $(CC) $^ $(LIB) -o $(BUILD_DIR)/main

%.o: %.cpp
 $(CC) $(C_FLAGS) -c $< -o $@ 
%_debug.o: %.cpp
 $(CC) -DDEBUG -DTIME $(C_FLAGS) -c $< -o $@ 
%_time.o: %.cpp
 $(CC) -DTIME $(C_FLAGS) -c $< -o $@ 


checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
 @mkdir -p $@

.PHONY: clean
clean:
 rm -rf $(BUILD_DIR)/main ${SRC_DIR}/*.o

将obj与src分离

CC = g++
MPICC = mpicc

C_FLAGS= -O3 -fopenmp 
LIB = -lgomp
# C_FLAGS= -fopenmp $(LIB) $(debugFlag)
# C_FLAGS= -O3 -march=znver1 -mavx2 -fopenmp $(LIB) $(debugFlag)

INCLUDEPATH = feGRASS
SRC_DIR = feGRASS
BUILD_DIR = build/bin
OBJ_DIR = build/obj

SRCS = $(wildcard $(SRC_DIR)/*.cpp)
TMP = $(patsubst %.cpp,${OBJ_DIR}/%.cpp,$(notdir ${SRCS}))
# example: $(patsubst %.cpp,%.d,$(patsubst %.c,%.d,$(patsubst %.cc,%.d,$(LIBCARBON_SOURCES)))) 
# 意思是把$(LIBCARBON_SOURCES)变量中的所有.cpp,.c,.cc文件名替换为.d文件名
HEADERS = $(wildcard $(SRC_DIR)/*.h)
OBJ = $(TMP:.cpp=.o)
DEBUG_OBJ = $(TMP:.cpp=_debug.o)
TIME_OBJ = $(TMP:.cpp=_time.o)
FILENAME = $(TMP:.cpp=)

$(info    SRCS is: $(SRCS))
$(info    OBJ is: $(OBJ))
$(info    HEADERS is: $(HEADERS))

.DEFAULT_GOAL := main
main : $(OBJ)
 $(CC) $(OBJ) $(LIB) -o $(BUILD_DIR)/main

debugPrint: $(DEBUG_OBJ)
 $(CC) $(DEBUG_OBJ) $(LIB) -o $(BUILD_DIR)/main

timePrint: $(TIME_OBJ)
 $(CC) $(TIME_OBJ) $(LIB) -o $(BUILD_DIR)/main

mpi: $(SRCS)
 $(MPICC) $^ $(C_FLAGS) -o $(BUILD_DIR)/main

debugMpi: $(SRCS)
 $(MPICC) -DDEBUG -DTIME $^ $(C_FLAGS) -o $(BUILD_DIR)/main

timeMpi: $(SRCS)
 $(MPICC) -DTIME $^ $(C_FLAGS) -o $(BUILD_DIR)/main

${OBJ_DIR}/%.o: ${SRC_DIR}/%.cpp $(HEADERS)
 $(CC) $(C_FLAGS) -c $< -o $@ 
${OBJ_DIR}/%_debug.o: ${SRC_DIR}/%.cpp $(HEADERS)
 $(CC) -DDEBUG -DTIME $(C_FLAGS) -c $< -o $@ 
${OBJ_DIR}/%_time.o: ${SRC_DIR}/%.cpp $(HEADERS)
 $(CC) -DTIME $(C_FLAGS) -c $< -o $@ 


checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
 @mkdir -p $(BUILD_DIR)
 @mkdir -p $(OBJ_DIR)


.PHONY: clean
clean:
 rm -rf $(BUILD_DIR)/main $(OBJ_DIR)/*.o

说明

  1. $(foreach var,list,text)的语法来对list中的每个元素执行text,并用var来引用当前元素1。你也可以用
  2. $(wildcard pattern)的语法来匹配指定模式的文件,并返回其列表
  3. $(subst from,to,text)的语法来把text中的from替换为to
  4. $(patsubst pattern,replacement,text)的语法来把text中匹配pattern的部分替换为replacement
  5. include <filenames> ,make 在处理程序的时候,文件列表中的任意一个文件不存在的时候或者是没有规则去创建这个文件的时候,make 程序将会提示错误并保存退出;
  6. -include <filenames>,当包含的文件不存在或者是没有规则去创建它的时候,make 将会继续执行程序,只有真正由于不能完成终极目标重建的时候我们的程序才会提示错误保存退出;
  7. addprefix的功能增加前缀,例如$(addprefix -I,./Inc)执行后为 -I ./Inc
  8. OUTPUT_FILES = $(addsuffix .out, $(addprefix $(OUTPUT_DIR)/, $(BENCH_MAINNAME)))
  9. 文件名处理函数 dir, notdir, suffix, basename (网站basename例子写错了)
  10. https://www.zhaixue.cc/makefile/makefile-filename-function.html
  11. .PHONY: clean是为了有clean名称的文件时,防止把make clean理解成生成clean文件,而不是使用clean规则。
  12. 一个Makefile文件里通常会有多个目标,一般会选择第一个作为默认目标。所以一般第一个写all
  13. 赋值符号 = 是最基本的赋值 := 是覆盖之前的值 ?= 是如果没有被赋值过就赋予等号后面的值 += 是添加等号后面的值
  14. makefile中命令前加一个@的作用是不让make显示出要执行的命令
  15. $@ is the name of the target being generated, and$< the first prerequisite (usually a source file). You can find a list of all these special variables in the GNU Make manual.

For example, consider the following declaration:

all: library.cpp main.cpp

In this case:

$@ evaluates to all

$< evaluates to library.cpp

$^ evaluates to library.cpp main.cpp

常见问题

Makefile:22: *** missing separator.  Stop.

命令开头要用Tab,不是空格。别用vscode,用vim写

复杂项目的例子

Victima模拟器(sniper拓展地址翻译的模拟器)

分析复杂的Makefile

# Victima/sniper/Makefile
STANDALONE=$(SIM_ROOT)/lib/sniper
$(STANDALONE): $(LIB_CARBON) $(LIB_SIFT) $(LIB_DECODER)
    @$(MAKE) $(MAKE_QUIET) -C $(SIM_ROOT)/standalone

# vscode-remote://ssh-remote%2Bicarus3/staff/shaojiemike/test/Victima/src/Victima/sniper/standalone/Makefile
LD_LIBS += -lcarbon_sim -lpthread -ldw
SOURCES = $(shell ls $(SIM_ROOT)/standalone/*.cc)
OBJECTS = $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCES)))
## build rules
TARGET = $(SIM_ROOT)/lib/sniper
$(TARGET): $(SIM_ROOT)/lib/libcarbon_sim.a $(SIM_ROOT)/sift/libsift.a $(SIM_ROOT)/decoder_lib/libdecoder.a
$(TARGET): $(OBJECTS)
    $(_MSG) '[LD    ]' $(subst $(shell readlink -f $(SIM_ROOT))/,,$(shell readlink -f $@))
    $(_CMD) $(CXX) $(LD_FLAGS) -o $@ $(OBJECTS) $(LD_LIBS) $(OPT_CFLAGS) -std=c++0x

解释

第一个规则:$(TARGET): $(SIM_ROOT)/lib/libcarbon_sim.a $(SIM_ROOT)/sift/libsift.a $(SIM_ROOT)/decoder_lib/libdecoder.a 这行定义了 $(TARGET)(即 $(SIM_ROOT)/lib/sniper)依赖于三个库文件。这意味着在构建 $(TARGET) 之前,必须首先存在或构建这些库文件。

第二个规则:$(TARGET): $(OBJECTS) 这行则说明 $(TARGET) 还依赖于由 $(OBJECTS) 定义的一系列对象文件。这是实际编译生成可执行文件所需要的对象文件。

参考文献

https://blog.csdn.net/ET_Endeavoring/article/details/98989066

LinuxCommand: system info

硬盘/挂载空间

df -h .

各个文件夹空间

deep为1

du -h -d .

进程查看与kill

# thi
ps aux | grep 1499321
ps -auxf | grep -nB 10 -E 'python[3]?|PID'
kill -9 

ps aux linux command whill show no zero cpu usage when the process is sleeping beacuse of its snapshots mechanism

apt-get problems

dpkg: 处理归档 /var/cache/apt/archives/bat_0.12.1-1build1_arm64.deb (--unpack)时出错:
 正试图覆盖 /usr/.crates2.json,它同时被包含于软件包 ripgrep 11.0.2-1build1
dpkg-deb: 错误: 粘贴 子进程被信号(断开的管道) 终止了
在处理时有错误发生:
 /var/cache/apt/archives/bat_0.12.1-1build1_arm64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)
sudo apt-get purge -h
# jsonfile conflict purge - Remove packages and config files

tree

deep size

tree -L DepthSIze Folder_Path

so文件分析

#分析symbols 
nm -gDC intel64/gcc4.8/*
  • -g:显示全局符号表。
  • -D:显示动态符号表。
  • -C:将 C++ 符号名还原成源代码中的名称。

综合来看,使用 nm -gDC <filename> 命令可以查看一个二进制可执行文件或者共享库中的全局符号表和动态符号表,并将包含其中的 C++ 符号名还原成源代码中的名称。

shaojiemike@snode6 ~/github/gem5  [10:49:56]
> nm /usr/local/lib/libprotobuf.a |c++filt|grep google::protobuf::MessageFactory::InternalRegisterGeneratedFile
                 U google::protobuf::MessageFactory::InternalRegisterGeneratedFile(char const*, void (*)(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&))
0000000000000e00 T google::protobuf::MessageFactory::InternalRegisterGeneratedFile(char const*, void (*)(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&))

#分析子so
ldd .so

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

Cpu Time

Situation

It is all started with two confusing situation.

  • I found out using ps aux | grep -v process_name, the process is in Sl+ state. But the cpu usage is not zero.
  • watch "ps aux |grep 3496617" always show the same cpu usage percentage, which is very confusing beacause htop always show up-down value. and pidstat -p 3516617 show cpu% less than 100%.

Git Standardization

workflow

内容模板

隐藏文件夹 .github , 里面放两个文件:

ISSUE_TEMPLATE.md

PULL_REQUEST_TEMPLATE.md

分支模型

Git Flow 分支模型

仓库有两个基础分支:

dev(默认分支)
master(用于发布)

通过pull request来合并新的代码:

协作者的代码通过pr合并到dev
dev通过pr合并到master

注意点:

merge 到 dev,使用squash merge
merge 到 master,使用普通的merge
永远不向master直接commit代码

GitHub Flow 分支模型

只有一个长期分支 master ,而且 master 分支上的代码,永远是可发布状态,

CI(Continuous Integration)集成

netlify

to do

github action

github自带的,貌似比Travis CI好用

ctest 怎么写

https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html

travis ci

Travis CI 提供的是持续集成服务(Continuous Integration,简称 CI)。它绑定 Github 上面的项目,只要有新的代码,就会自动抓取。然后,提供一个运行环境,执行测试,完成构建,还能部署到服务器。

持续集成的好处在于,每次代码的小幅变更,就能看到运行结果,从而不断累积小的变更,而不是在开发周期结束时,一下子合并一大块代码。

  1. 使用准备
  2. 登录 https://app.travis-ci.com/ ,绑定github,选择监听仓库.
  3. 项目里面有可运行的代码,项目还包含构建或测试脚本
  4. .travis.yml
  5. 在项目根目录下新建 .travis.yml 文件。参考官方文档编写 https://docs.travis-ci.com/user/languages/cpp/
  6. 运行流程
  7. install 阶段:安装依赖
  8. script 阶段:运行脚本
  9. 可选部分
before_install:install 阶段之前执行
before_script:script 阶段之前执行
after_failure:script 阶段失败时执行
after_success:script 阶段成功时执行
before_deploy:deploy 步骤之前执行
after_deploy:deploy 步骤之后执行
after_script:script 阶段之后执行
  1. 运行状态
passed:运行成功,所有步骤的退出码都是0
canceled:用户取消执行
errored:before_install、install、before_script有非零退出码,运行会立即停止
failed :script有非零状态码 ,会继续运行
  1. 可选加密环境变量

git commit 规范

Angular规范

<type>(<scope>): <subject>

type 必须

name description
feat: 新功能(feature)。
fix/to: 修复bug,可以是QA发现的BUG,也可以是研发自己发现的BUG。
fix: 产生diff并自动修复此问题。适合于一次提交直接修复问题
to: 只产生diff不自动修复此问题。适合于多次提交。最终修复问题提交时使用fix
docs: 文档(documentation)。
style: 格式(不影响代码运行的变动)。
refactor: 重构(即不是新增功能,也不是修改bug的代码变动)。
perf: 优化相关,比如提升性能、体验。
test: 增加测试。
chore: 构建过程或辅助工具的变动。
revert: 回滚到上一个版本。
merge: 代码合并。
sync: 同步主线或分支的Bug。

规范化commit message

格式为:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
  1. 对于Revert: If the commit reverts a previous commit, it should begin with revert:, followed by the header of the reverted commit. In the body it should say: This reverts commit <hash>., where the hash is the SHA of the commit being reverted.
  2. type的类型有:

  3. feat: A new feature

  4. fix: A bug fix
  5. docs: Documentation only changes
  6. style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)空白、格式、缺少分号等
  7. refactor:(重构) A code change that neither fixes a bug nor adds a feature
  8. perf: A code change that improves performance
  9. test: Adding missing or correcting existing tests
  10. chore: (琐事)Changes to the build process or auxiliary tools(辅助工具) and libraries such as documentation generation

  11. scope: commit 改变的位置,如果是多处写*

  12. subject: 简明的描述:
  13. 使用祈使句,现在时态
  14. 不要.结尾
  15. 第一个字母不要大写
  16. body: 包括改变的动机,并将其与以前的行为进行对比。
  17. footer: Breaking Changes或者reference GitHub issues that this commit closes. Breaking Changes should start with the wordBREAKING CHANGE: with a space or two newlines. The rest of the commit message is then used for this.

自动生成Release Notes

规范化commit

插件 vscode插件git-commit-plugin

命令行 husky + commitlint

工具

  1. Standard Version
  2. 实现自动化版本控制,自动创建changelog, 创建 git tags
  3. 安装
npm cache clean --force #npm指令清除npm缓存
# 删除node_module包
npm install -g npm # npm 更新到最新
npm install -g n
n latest # node 更新
   Note: the node command changed location and the old location may be remembered in your current shell.
            old : /usr/bin/node
            new : /usr/local/bin/node
   To reset the command location hash either start a new shell, or execute PATH=$PATH"
PATH=/usr/local/bin/:$PATH
npm install -D standard-version
  1. 编写package.json
"scripts": {
   "release": "standard-version"
}
  1. CHANGELOG.md 记录内容的配置

    1. 创建.versionrc
    {
    "types": [
       {"type": "chore", "section":"Others", "hidden": false},
       {"type": "revert", "section":"Reverts", "hidden": false},
       {"type": "feat", "section": "Features", "hidden": false},
       {"type": "fix", "section": "Bug Fixes", "hidden": false},
       {"type": "improvement", "section": "Feature Improvements", "hidden": false},
       {"type": "docs", "section":"Docs", "hidden": false},
       {"type": "style", "section":"Styling", "hidden": false},
       {"type": "refactor", "section":"Code Refactoring", "hidden": false},
       {"type": "perf", "section":"Performance Improvements", "hidden": false},
       {"type": "test", "section":"Tests", "hidden": false},
       {"type": "build", "section":"Build System", "hidden": false},
       {"type": "ci", "section":"CI", "hidden":false}
    ]
    }
    
  2. 使用Standard Version

// 初次发布版本
npm run release --first-release
npm run release #(自动更新版本号,自动更新 CHANGELOG.md, 自动创建 git tag)
git push --follow-tags origin master
  1. 寄
  2. Commitizen for contributors
  3. Linux下commit规范辅助,用来选择(没vscode的时候用)
  4. 用 git-cz 来提交文件
  5. https://www.jianshu.com/p/acfdd4ca0104
  6. Visual Studio Code Commitizen Support vscode的插件
  7. conventional-changelog/commitlint 阻止不规范的提交

github-release-notes

github-release-notes,以下简称 gren ,是用来一键向 github 发布 release notes 的工具。 https://zhuanlan.zhihu.com/p/99499246

https://blog.csdn.net/weixin_39586683/article/details/110643111

release 语义化版本 semver

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

主版本号:当你做了不兼容的 API 修改, 次版本号:当你做了向下兼容的功能性新增, 修订号:当你做了向下兼容的问题修正。 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

Git auto-release requirements

  1. github Actions / travis-ci
  2. 自动化测试
  3. Commitizen / Visual Studio Code Commitizen Support
  4. 规范commit message
  5. standard-version
  6. 更新 package 版本并打 tag
  7. github-release-notes
  8. 生成 release-log

需要进一步的研究学习

写个github模板

  1. 明确文件结构
  2. src/include/build/Doc/Debug/test/example
  3. 清晰的README
  4. Intro/Install&Run/Features/Bugs/Acknowledge
  5. 图片和标签
    1. https://shields.io/category/build
  6. Release的自动发布
  7. 规范commit
  8. 其他自动化的轮子持续整合 (Continuous Integration, CI)
  9. travis ci
  10. github action
    1. ctest 怎么写?
  11. cmake.yml
  12. .github/workflow
    1. https://github.com/iBug/AWS-Lambda-webhook-py/tree/master/.github/workflows
    2. https://github.com/Kirrito-k423/github-stats
  13. 文档生成
    1. doxygen
    2. Doxygen主要解决说明书问题,可以在我们写代码的时候讲注释转化为说明书,Graphviz主要是用于图形展示
    3. 有项目,文件,函数三部分的书写要求 https://www.cnblogs.com/silencehuan/p/11169084.html
  14. Codecov
    1. 代码覆盖率,执行部分占比。因为未执行部分可能是错的
  15. projects/ bug fixs
  16. 设置为 template repository
  17. 查看 https://app.travis-ci.com/github/Kirrito-k423/githubTemplate

plus

将网站变成带名字的md格式参考文献的插件

Boost 设置

set(Boost_USE_STATIC_LIBS ON)

set(Boost_DEBUG ON)

Boost_INCLUDE_DIR: 含有boost头文件的目录 Boost_LIBRARYDIR: 偏好的含有boost库的库目录

https://stackoverflow.com/questions/3897839/how-to-link-c-program-with-boost-using-cmake

Boost Install

http://c.biancheng.net/view/7772.html cache?

cmake boost install path

https://cloud.tencent.com/developer/ask/107360

设置boost-root 查看安装位置

Travis-CI Install

Travis-CI 依赖软件包每次都要重新安装吗

apt-get install in a GitHub Actions workflow

https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow

Actions may have no Boost, where

ctest

Ctest add build/bin to test

Ctest https://www.cnblogs.com/hustcpp/p/12922998.html

https://blog.csdn.net/zcteo/article/details/117527823?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-15.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-15.no_search_link

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

还是ipcc的github组织的太烂了,需要学习一下

参考文献

https://zhuanlan.zhihu.com/p/67620599

http://www.ruanyifeng.com/blog/2017/12/travis_ci_tutorial.html

https://github.com/levy9527/blog/issues/1

Linux Executable file: Structure & Running 2

可执行文件的运行

要运行可执行目标文件 prog,我们可以在 Linux shell 的命令行中输入它的名字: linux> ./prog 因为 prog 不是一个内置的 shell 命令,所以 shell 会认为 prog 是一个可执行目标文件。

进程的启动

  • Linux进程的启动是通过父进程复制一个子进程,子进程通过execve系统调用启动加载器。
  • 加载器(loader)删除子进程已有的虚拟存储段,
  • 通过将虚拟地址空间中的页映射到可执行文件的页大小组块,
  • 并创建一组新的代码、数据、堆、栈段,
  • 同时新的堆和栈被初始化为零。
  • 新的代码和数据段被初始化为可执行文件的内容,
  • 最后将CUP指令寄存器设置成可执行文件入口,启动运行。

执行完上述操作后,其实可执行文件的真正指令和数据都没有别装入内存中。操作系统只是通过可执行文件头部的信息建立起可执行文件和进程虚拟内存之间的映射关系而已。

memory map

除了一些头部信息,在加载过程中没有任何从磁盘到内存的数据复制。直到 CPU 引用一个被映射的虚拟页时才会进行复制,此时,操作系统利用它的页面调度机制自动将页面从磁盘传送到内存。

比如,现在程序的入口地址为 0x08048000 ,刚好是代码段的起始地址。当CPU打算执行这个地址的指令时,发现页面 0x8048000 ~ 0x08049000 (一个页面一般是4K)是个空页面,于是它就认为是个页错误。此时操作系统根据虚拟地址空间与可执行文件间的映射关系找到页面在可执行文件中的偏移,然后在物理内存中分配一个物理页面,并在虚拟地址页面与物理页面间建立映射,最后把EXE文件中页面拷贝到内存的物理页面,进程重新开始执行。该过程如下图所示:

接下来,加载器跳转到程序的入口点,也就是 _start函数的地址。这个函数是在系统目标文件 ctrl.o 中定义的,对所有的 C 程序都是一样的。_start 函数调用系统启动函数 __libc_start_main,该函数定义在 libc.so 中。它初始化执行环境,调用用户层的 main 函数,处理 main 函数的返回值,并且在需要的时候把控制返回给内核。

fork 和 execve 函数的差异

  • fork 函数在新的子进程中运行相同的程序,新的子进程是父进程的一个复制品。
  • execve 函数在当前进程的上下文中加载并运行一个新的程序。
  • 它会覆盖当前进程的地址空间,但并没有创建一个新进程。
  • 新的程序仍然有相同的 PID,并且继承了调用 execve 函数时已打开的所有文件描述符。

程序运行途中修改exe程序

  • 由于操作系统使用页表和虚拟内存机制来实现按需加载。按需加载意味着只有在程序执行到需要访问某个代码段时,才会将该代码段从可执行文件加载到内存中。
  • 那么如果我在程序运行的途中重新编译程序,修改了代码段,那么程序会怎么样呢?
  • Chatgpt:运行中的程序尝试执行新的代码时,会发生未定义的行为,因为操作系统不会自动将新的代码加载到正在运行的进程的内存中。
  • 一个页表4KB,一个程序的代码段可能有如下100KB甚至几十MB,不可能全部加载。
# shaojiemike @ snode6 in ~/github/sniper_PIMProf/PIMProf/gapbs on git:dev o [15:15:29]
$ size /usr/lib/llvm-10/bin/llvm-mca
   text    data     bss     dec     hex filename
 144530    6056    8089  158675   26bd3 /usr/lib/llvm-10/bin/llvm-mca

# shaojiemike @ snode6 in ~/github/sniper_PIMProf/PIMProf/gapbs on git:dev o [15:18:14]
$ l /usr/lib/llvm-10/bin/llvm-mca
-rwxr-xr-x 1 root root 153K Apr 20  2020 /usr/lib/llvm-10/bin/llvm-mca

程序运行途中修改python代码

  • 虽然修改python代码类似修改C代码,按理来说不会影响程序进行。但是python是逐行解释执行的,很难让人不思考会不会影响正在运行中的程序。
  • 答案是不会,原因有二:
  • python代码在运行时,会被编译成字节码,然后再执行字节码。修改python代码后,其对应的字节码会在下一次运行程序时,Python解释器对比文件时间戳时更新。
  • Python解释器在运行时,会将所需的文件提前加载到内存里

GDB调试修改

Memalloc

2

Buddy 内存分配

是一种用于管理计算机内存的算法,旨在有效地分配和释放内存块,以防止碎片化并提高内存的使用效率。这种算法通常用于操作系统中,以管理系统内核和进程的内存分配。

Buddy 内存分配算法的基本思想是将物理内存划分为大小相等的块,每个块大小都是 2 的幂次方。每个块可以分配给一个正在运行的进程或内核。当内存被分配出去后,它可以被分割成更小的块,或者合并成更大的块,以适应不同大小的内存需求。

算法的名称 "Buddy" 来自于分配的块之间的关系,其中一个块被称为 "buddy",它是另一个块的大小相等的邻居。这种关系使得在释放内存时,可以尝试将相邻的空闲块合并成更大的块,从而减少内存碎片。

Buddy 内存分配算法的工作流程大致如下:

  1. 初始时,整个可用内存被视为一个大块,大小是 2 的幂次方。

  2. 当一个进程请求内存分配时,算法会搜索可用的块,找到大小合适的块来满足请求。如果找到的块比所需的稍大,它可以被分割成两个相等大小的 "buddy" 块,其中一个分配给请求的进程。

  3. 当一个进程释放内存时,该块会与其 "buddy" 块合并,形成一个更大的块。然后,这个更大的块可以与其它相邻的块继续合并,直到达到较大的块。

Buddy 内存分配算法在一些操作系统中用于管理内核和进程的物理内存,尤其在嵌入式系统和实时操作系统中,以提高内存使用效率和避免碎片化问题。

ucore(Micro-kernel Operating System for Education)

是一个用于教育目的的微内核操作系统

linux遇到问题

我们可window写程序占满16G内存

但是linux,用了3GB就会seg fault

猜想是不是有单进程内存限制 https://www.imooc.com/wenda/detail/570992

而且malloc alloc的空间在堆区,我们可以明显的发现这个空间是被栈区包住的,有限的。windows是如何解决这个问题的呢? 1. 首先这个包住是虚拟地址,通过页表映射到的物理地址是分开的 2. 根据第一点,可以实现高地址动态向上移动

动态数据区一般就是“堆栈”。“栈 (stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然 代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数 据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

当进程初始化时,系统会自动为进程创建一个默认堆,这个堆默认所占内存的大小为1M。堆对象由系统进行管理,它在内存中以链式结构存在。

Linux 单进程内存限制

/etc/security/limits.conf

# shaojiemike @ node5 in ~ [6:35:51]
$ ulimit -a
-t: cpu time (seconds)              unlimited
-f: file size (blocks)              unlimited
-d: data seg size (kbytes)          unlimited
-s: stack size (kbytes)             8192
-c: core file size (blocks)         0
-m: resident set size (kbytes)      unlimited
-u: processes                       513967
-n: file descriptors                1024
-l: locked-in-memory size (kbytes)  65536
-v: address space (kbytes)          unlimited
-x: file locks                      unlimited
-i: pending signals                 513967
-q: bytes in POSIX msg queues       819200
-e: max nice                        0
-r: max rt priority                 0
-N 15:                              unlimited

ulimit -HSn 4096 # H指定了硬性大小,S指定了软性大小,n表示设定单个进程最大的打开文件句柄数量。硬限制是实际的限制,而软限制,是warnning限制,只会做出warning

lsof
文件描述符

文件句柄数

这些限制一般不会限制内存。

超算登录节点任务限制的实现

GNU malloc()

调用malloc(size_t size)函数分配内存成功,总会分配size字节VM(再次强调不是RAM),并返回一个指向刚才所分配内存区域的开端地址。分配的内存会为进程一直保留着,直到你显示地调用free()释放它(当然,整个进程结束,静态和动态分配的内存都会被系统回收)。

GNU libc库提供了二个内存分配函数,分别是malloc()和calloc()。glibc函数malloc()总是通过brk()或mmap()系统调用来满足内存分配需求。函数malloc(),根据不同大小内存要求来选择brk(),还是mmap(),阈值 MMAP_THRESHOLD=128Kbytes是临界值。小块内存(<=128kbytes),会调用brk(),它将数据段的最高地址往更高处推(堆从底部向上增长)。大块内存,则使用mmap()进行匿名映射(设置标志MAP_ANONYMOUS)来分配内存,与堆无关,在堆之外。

malloc不是直接分配内存的,是第一次访问的时候才分配的?

https://www.zhihu.com/question/20836462

问题

  1. 堆区和栈区是进程唯一的吗?
  2. 是的,而且栈主要是为一个线程配备,小可以保证基本在cache里
  3. 两个操作系统的malloc的是物理内存还是虚拟内存
  4. Linux采用的是copy-on-write机制

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

每次都是6008这里,40000*6008*3/1024/1024=687MB 733448/1024=716MB 问了大师兄,问题竟然是malloc的传入参数错误的类型是int,导致存不下3*40*1024*40*1024。应该用size_t类型。(size_t是跨平台的非负整数安全类型)

参考文献

https://blog.csdn.net/shenzi/article/details/3972437?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.base&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.base

程序(进程)内存空间分布深入理解

Firewall

简介

防火墙是一种网络安全设备,主要是通过硬件和软件的作用于内部和外部网络的环境间产生一种保护的屏障,从而实现对计算机不安全网络因素的阻断。 * 所有流入流出的所有网络通信均要经过此防火墙。 * 功能 * 访问控制、隔离保护 * 组成 * 服务访问政策、验证工具、包过滤和应用网关

功能作用

  • 入侵检测功能
  • 主要有反端口扫描、检测拒绝服务工具、检测CGI/IIS服务器入侵、检测木马或者网络蠕虫攻击、检测缓冲区溢出攻击等功能,
  • 可以极大程度上减少网络威胁因素的入侵,有效阻挡大多数网络安全攻击。
  • 网络地址转换功能(NAT)
  • 分为源地址转换和目的地址转换,即SNAT和DNAT。可以由服务的发起者是谁来区分两者。
  • SNAT: 内部地址要访问公网上的服务时,内部地址会主动发起连接,将内部地址转换成公有ip
    • 修改源ip地址的目的一般都是为了让这个包能再回到自己这里,所以在iptables中,SNAT是在出口,也即POSTROUTING链发挥作用。
    • SNAT主要用于隐藏内部网络结构,避免受到来自外部网络的非法访问和恶意攻击,有效缓解地址空间的短缺问题,
  • DNAT:当内部需要对外提供服务时,外部发起主动连接公有ip的网关,路由器或着防火墙的网关接收到这个连接,然后把连接转换到内部,此过程是由带公有ip的网关代替内部服务来接收外部的连接,然后在内部做地址转换。
    • 修改目的ip地址的原因一般就是为了改变包发送的目的地,让包走出去,而不是留下来,所以在iptables中,DNAT是在入口,也即PREROUTING链中发挥作用,以便让包进入FORWARD表。
    • DNAT主要用于外网主机访问内网主机,以此避免内部网络被攻击。
    • DNAT与端口转发的区别在哪里?
  • 网络操作的审计监控功能
  • 对系统管理的所有操作以及安全信息进行记录,提供有关网络使用情况的统计数据,方便计算机网络管理以进行信息追踪。
  • 强化网络安全服务(类似GFW)
  • 集中化的安全管理,将安全系统装配在防火墙上,在信息访问的途径中就可以实现对网络信息安全的监管。

Linux实现原理

  • Linux系统内核中的安全框架Netfilter,为其他内核模块提供数据包过滤、网络地址转换(NAT)和负载均衡的功能。
  • 常用的iptables和firewalld服务都依赖于Netfilter来过滤数据包,两者自身并不具备防火墙的功能,只是创建并维护规则。
  • 不同之处在于iptables基于“过滤规则链”,firewalld基于zone区域。
  • iptables无守护进程,不能算作真正的服务,firewalld存在守护进程

三表五链 - 三表(应用规则)

  • filter 用于过滤,防火墙,过滤数据包
  • nat 用于网络地址转换、端口转发
  • mangle 用于拆解报文,作出修改,封装报文
  • raw表, 关闭nat表上启用的连接追踪机制,以提高性能。
  • 表规则应用优先级:raw>mangle>nat>filter
  • 每个表中能存在的链如下

三表五链 - 五链(数据包状态/ 过滤规则链)

  • PREROUTING 进入路由之前的数据包
  • INPUT 目的地址为本机的输入数据包
  • FORWARD 目的地址不为本机的包,可以实现转发(需要开启)
  • OUTPUT 源地址为本机的输出数据包
  • POSTROUTING 发送到网卡之前的数据包

Nftables

  • Allows configuration of tables, chains and rules provided by the Linux kernel firewall.
  • Nftables replaces iptables.
  • 解决的iptables的不足
    • 不同协议实现的代码重复
    • Nftables通过增强的通用集和映射基础结构,可以更快地进行数据包分类。
    • 解决语法不一致的问题,并提供更好,更紧凑的语法。
  • OpenWRT和ubuntu都使用Nftables

与iptables表的对应关系

nftables簇 iptables实用程序
ip iptables
ip6 ip6tables
inet iptables和ip6tables
arp arptables
bridge ebtables
  • ip(即IPv4)是默认簇,如果未指定簇,则使用该簇。
  • 创建同时适用于IPv4和IPv6的规则,请使用inet。inet允许统一ip和ip6簇,以便更容易地定义规则。

输出解释

table inet warp {
        chain warp-in {
                type filter hook input priority mangle; policy accept;
                ip6 saddr 2606:4700:d0::a29f:c001 udp sport 1701 @th,72,24 set 0x0
        }

        chain warp-out {
                type filter hook output priority mangle; policy accept;
                ip6 daddr 2606:4700:d0::a29f:c001 udp dport 1701 @th,72,24 set 0x46c997
        }
}
  • type 可以是filterroute或者nat
  • hook 在IPv4/IPv6/Inet地址簇中,可以是preroutinginputforwardoutput或者postrouting。其他地址簇中的钩子列表请参见nft(8)。

iptables命令

查看默认表filter的规则

对于每条链,内核会按照顺序依次检查 iptables 防火墙规则,如果发现有匹配的规则目录,则立刻执行相关动作,停止继续向下查找规则目录;如果所有的防火墙规则都未能匹配成功,则按照默认策略处理。

$ sudo iptables -vnL 
Chain INPUT (policy ACCEPT 2211K packets, 855M bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  tun0   *       0.0.0.0/0            0.0.0.0/0

  • 命令
  • 默认 -t filter
  • -v 显示详细信息,-n显示具体ip和端口数值
  • 输出
  • policy ACCEPT 当前链的默认策略 ACCEPT
  • pkts:对应规则匹配到的报文的个数。
  • bytes:对应匹配到的报文包的大小总和。
  • target:规则对应的target,往往表示规则对应的"动作",即规则匹配成功后需要采取的措施。
  • prot:表示规则对应的协议,是否只针对某些协议应用此规则。
  • opt:表示规则对应的选项。
  • in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。
  • out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。
  • source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
  • destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。

添加的动作

命令部分:-j + 如下动作 * ACCEPT:允许数据包通过。 * DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。 * REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。 * SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。 * MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。 * DNAT:目标地址转换。 * REDIRECT:在本机做端口映射。 * LOG:在/var/log/messages文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配。

iptables管理命令

  • 选择表
  • -t指定表
  • 添加新规则
  • -A在链的最后追加一条规则 
  • -I在链的开头或指定序号插入一条规则 
  • -x显示精确值,不做单位换算
  • 替换规则
  • -R替换一条指定的规则
  • 查看规则
  • -L列出所有规则 
  • -n以数据形式显示地址与端口信息 
  • -v以更加详细的方式显示 
  • --line-numbers查看规则时,显示规则序号
  • 删除或清空规则
  • -D删除指定序号的一条规则 
  • -F清空指定表中的所有规则
  • 设置默认策略
  • -P为指定的链设置默认规则
  • 新建规则链
  • -N新建自定义链
  • 重命名链
  • -E重命名自定义链
  • 删除链
  • -X删除自定义空链 
  • -Z计数器清零

常见实例

Add a NAT rule to translate all traffic from the 192.168.0.0/24 subnet to the host's public IP:

$sudo iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

$ sudo iptables -t nat -vnL --line-numbers
Chain POSTROUTING (policy ACCEPT 19 packets, 1551 bytes)
num   pkts bytes target     prot opt in     out     source               destination
6        0     0 MASQUERADE  all  --  *      *       192.168.0.0/24       0.0.0.0/0

$ sudo iptables -t nat -D POSTROUTING 6 #delete

有待学习

  • docker相关的iptables的输出
  • OpenWRT上iptables完全是空的,是显示错误还是防火墙用了firewalld
  • node5上的warp的mangle在哪里?

Ubuntu配置

Windows配置

  • 入站规则
  • 出站规则

OpenWRT配置

to finished

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://blog.csdn.net/weixin_45649763/article/details/103338747

https://juejin.cn/post/7108726951304495135

https://icloudnative.io/posts/using-nftables/

Jupyter AI

Jupyter 简介

Jupyter是一个开源的、交互式的计算环境,可以让用户创建和共享包含实时代码、可视化和文本的文档。

  • 它的名字来源于三个主要的编程语言:Julia、Python和R,这三种语言的开头字母构成了“Jupyter”。
  • Jupyter最初是IPython项目的一部分,旨在提供Python的交互式计算环境。随着时间的推移,它不仅支持Python,还扩展到其他编程语言,包括R、Julia、Scala等。Jupyter的灵感来自于IPython的交互式shell,但在其基础上增加了更多功能和可扩展性。

Jupyter最显著的特点:用户可以通过Web浏览器打开Jupyter笔记本,然后在其中编写代码、运行代码并直接查看代码的输出结果。笔记本中的代码和文本可以交叉编排,使得写作、数据分析和可视化变得非常直观和便捷。

主要的Jupyter组件包括:

  1. Jupyter Notebook:这是最常见的Jupyter界面,以.ipynb后缀的文件保存。它支持多种编程语言的代码运行,交互式地执行和编辑代码块,并支持在代码块中插入Markdown格式的文本以及图像、链接等内容。
  2. Jupyter Lab:这是Jupyter Notebook的下一代界面,提供了更加现代化和灵活的界面。Jupyter Lab将各种组件整合到一个集成的界面中,使得多个笔记本、终端和文件浏览器可以在一个窗口中同时运行。
  3. Jupyter Kernel:Jupyter支持多种编程语言的内核,通过内核,Jupyter可以与特定编程语言进行交互。例如,使用Python内核可以在笔记本中运行和编写Python代码,同样,使用R内核可以运行和编写R代码。

Jupyter在教育、数据科学、机器学习、数据分析等领域得到广泛应用。它提供了一个方便、实用的平台,帮助用户探索数据、实验算法、展示结果,并通过共享笔记本方便地与其他人交流和合作。

Jupyter vs python

Jupyter 的核心在于 数据分析的 计算-分析-可视化 的快速迭代。

如果不是数据科学,就不太需要Jupyter

Installation in Linux

安装Jupyter Lab

web-forward to local machine

远程访问服务器

Jupyter-AI

  1. Installation
  2. test

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

  1. python 一大特点就是容易可视化,既然这样,我为什么不用jupyter呢?
  2. chatgpt 类的工具都是基于付费API,有两大问题
  3. 国内难以付费
  4. 国内ip一旦访问是很容易封号的。
  5. 一种解决办法是使用有免费API的工具,并且在全流量走cloudflare的wg的服务器上配置服务。

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。

https://jupyter-ai.readthedocs.io/en/latest/users/index.html#installation

Parallel_sort

并行排序算法

to learn

PSRS算法

并行正则采样排序算法

PSRS

复杂度分析

简单地讨论一下 PSRS 算法的复杂度。

  • 在第一部分的快速排序中,时间复杂度为O(klogk),k=n/p
  • 然后,各处理器选择 p-1 个代表元素,代价为O(p)
  • 再由 Proc#0 对所有送来的代表元素进行排序,然后选出主元,这里若使用快速排序,代价为O(p^2 logp^2)
  • 而若使用归并排序,则所需代价为O(p^2)
  • 每个处理器接收到主元后,再对有序数组进行划分,代价为O(k+p)
  • 最后,各个处理器全局交换,并行归并排序,
  • 每个处理器是串行的多路归并问题,时间复杂度为O(k*logp)

考虑到实际应用中,需要排序的数据长度 n 一定远远多于现有的处理器 p,此时可以视 p 为一个小常数,那么 PSRS 排序算法的时间复杂度,就可以简化为 O(klogk+k*logp)~O(klogk)

从消息复杂度的角度看,

  • 播送主元的复杂度为 O(p^2+p)
  • 分区合并(全局交换)部分的消息复杂度与具体算法实现相关,但其最大值不会超过 O(n)

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。

https://dingfen.github.io/mpi&openmp/2021/01/23/psrs_sort.html