夏虫的博客

却道天凉好个秋

总结下python import的零碎知识

import的作用

import语句用来导入其他python文件(称为模块module),使用该模块里定义的类、方法或者变量,从而达到代码复用的目的。

import 的基本用法:

基本概念:

  • 模块(module):一般是以.py结尾的python文件,也可以是”.pyo”、”.pyc”、”.pyd”、”.so”、”.dll”结尾的文件。

模块可以定义函数、类、变量,也能包含可执行的代码。module来源有3种:
①Python内置的模块(标准库);
②第三方模块;
③自定义模块。

  • 包(package):含有Python模块的文件夹

用法一:import []

1
import [module_name\package_name]

Python会在两个地方寻找这个模块,

第一是sys.path(通过运行代码import sys; print(sys.path)查看),os这个模块所在的目录就在列表sys.path中,一般安装的Python库的目录都可以在sys.path中找到,所以对于安装好的库,我们直接import即可。

第二个地方就是运行文件所在的目录

用法二:from [] import []

从包中引入模块的import语句如下:

1
from [module_name\package_name] import [module_name\package_name\method]

导入一个包的时候,实际上就是导入包里面的__init__.py作为模块

import的工作原理

下面解析一下python的导入是如何工作的。假设你导入了一个abc模块。

1
import abc

python 是如何找到这个模块的呢?

  1. 首先,python会在sys.modules中查找这个模块名,sys.modules是先前曾被导入过的所有模块的缓存。简单来说,就是之前被导入过的模块,都被暂时保存在里面。

  2. 如果在缓存中找不到这个模块,python接下来会在内置的模块(标准库)中寻找

  3. 如果内置模块也找不到,Python将会去sys.path 定义的文件夹列表中搜索,sys.path 中默认的路径为:

    • 当前目录的路径,自定义的模块就是在这里被找到的。
    • 环境变量 PYTHONPATH 中指定的路径列表
    • Python 安装路径的 lib 目录所在路径

如果以上步骤都找不到这个模块,python会报错ModuleNotFoundError

详解 Python import 机制 (一):import 中的基本概念 - 知乎 (zhihu.com)

__all__变量暴漏接口

python _all__用法-徐徐图之-的博客-CSDN博客

__init__文件

一、GNU 工具链内容

工具链包含以下内容:

  • gcc(GNU C Compiler):编译器
  • C运行库:包括glibc、newlib、musl三种运行库,为C标准库提供函数实现支持,可以根据需求进行自定义修改。
  • Binutils:二进制程序处理工具,包括ar(静态库处理)、as(汇编器)、ld(链接器)等。
  • GDB:用于项目调试。
  • DeJaGNU:程序测试框架,为所有测试提供一个前端支持。

二、运行时库

riscv-gnu-toolchain 工具链分为elf-gcclinux-gnu-gcc两个版本,以及他们对应的32位和64位版本。两个的主要区别在于:

  • elf-gcc:(riscv32-unknown-elf-*,riscv64-unknown-elf-*)使用的newlib库(面向嵌入式的C库),而且只支持静态链接,不支持动态链接。
  • linux-gnu-gcc:(riscv32-unknown-linux-gnu-*,riscv64-unknown-linux-gnu-*)使用的是glibc标准库支持动态链接

从名字上便可以区分两者的使用场景,如果是编译简单,较小的elf程序,使用elf-gcc版本即可,如果编译比较大的程序或者需要动态库(比如编译linux,或opencv库等),推荐使用linux-gnu-gcc版本。

newlib

newlib是redhat社区维护的一个C运行时库,与glibc相比,其最大的特点是代码体积小、可移植性强,特别适合嵌入式开发环境

例如,newlib重写了printf、scanf、malloc函数,减少调用开销;并默认开启-Os编译开关,对代码体积进行压缩。

glibc

musl

三、Binutils工具介绍

  • as:汇编器
  • ld:链接器
  • ar:生成静态链接库
  • ldd:查看一个可执行程序所需要的依赖库
  • size:查看一个可执行程序各部分的大小(数据段、代码段等)

四、安装步骤

Step 1:安装依赖工具

1
sudo apt-get install git autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf patchutils bc libexpat-dev libglib2.0-dev ninja-build zlib1g-dev pkg-config libboost-all-dev libtool libssl-dev libpixman-1-dev libpython-dev virtualenv libmount-dev libsdl2-dev

Step 2:下载riscv工具链

github项目:riscv-collab/riscv-gnu-toolchain: GNU toolchain for RISC-V, including GCC (github.com)

1
git clone https://github.com/riscv-collab/riscv-gnu-toolchain.git

**gitee项目:**https://gitee.com/mirrors/riscv-dejagnu

1
git clone https://gitee.com/mirrors/riscv-gnu-toolchain

ps:最好用github,它是最新的

Step 3:下载各种submodule

下载 RISC-V 平台的 C 语言编译器源代码仓库

1
git clone -b riscv-gcc-10.2.0 https://gitee.com/mirrors/riscv-gcc

下载测试框架源代码仓库,即 riscv-dejagnu

1
git clone https://gitee.com/mirrors/riscv-dejagnu

下载 GNU 的 C 库源代码仓库,也就是 riscv-glibc

1
git clone -b riscv-glibc-2.29 https://gitee.com/mirrors/riscv-glibc

下载用于嵌入式的轻量级 C 库源代码仓库,即 riscv-newlib

1
git clone https://gitee.com/mirrors/riscv-newlib

下载二进制工具集合源代码仓库 riscv-binutils

1
git clone -b riscv-binutils-2.35 https://gitee.com/mirrors/riscv-binutils-gdb riscv-binutils

下载 GDB 软件调试器源代码仓库 riscv-gdb

1
git clone -b fsf-gdb-10.1-with-sim https://gitee.com/mirrors/riscv-binutils-gdb riscv-gdb

Step 3:使用./configure进行配置

1
./configure --prefix=xxx --with-arch=xxx --with-abi=xxx

(–prefix=)选项

安装后的目标文件夹

例如--prefix=/opt/riscv/,则安装后的可执行文件如下:

image-20240226193037166

(–with-arch=)选项

由于RISC-V的指令集是模块化的指令集,因此在为目标RISC-V平台进行交叉编译之时,需要通过选项指定目标RISC-V平台所支持的模块化指令集组合,该选项为(-march=),有效的选项值如下:

  • rv32i[m][a][f[d]][c]
  • rv32g[c]
  • rv64i[m][a][f[d]][c]
  • rv64g[c]

注意:在上述选项中rv32表示目标平台是32位架构,rv64表示目标平台是64位架构,其他i/m/a/f/d/c/g分别代表了RISC-V模块化指令子集的字母简称。

(–with-abi=)选项

由于RISC-V的指令集是模块化的指令集,因此在为目标RISC-V平台进行交叉编译之时,需要通过选项指定嵌入式RISC-V目标平台所支持的ABI函数调用规则

RISC-V定义了两种整数的ABI调用规则和三种浮点ABI调用规则,通过选项(-abi=)指明,有效的选项值如下:

  • ilp32
  • ilp32f
  • ilp32d
  • lp64
  • lp64f
  • lp64d

在上述选项中两种前缀(ilp32和lp64)表示的含义如下:

  • 前缀ilp32表示目标平台是32位架构,在此架构下,C语言的“int”和“long”变量长度为32比特,“long long”变量为64位;
  • 前缀lp64表示目标平台是64位架构,C语言的“int”变量长度为32比特,而“long”变量长度为64比特。

上述选项中的三种后缀类型(无后缀、后缀f、后缀d)表示的含义如下:

  • 无后缀:在此架构下,如果使用了浮点类型的操作,直接使用RISC-V浮点指令进行支持。但是当浮点数作为函数参数进行传递之时,无论单精度浮点数还是双精度浮点数均需要通过存储器中的堆栈进行传递。
  • f:表示目标平台支持硬件单精度浮点指令。在此架构下,如果使用了浮点类型的操作,直接使用RISC-V浮点指令进行支持。但是当浮点数作为函数参数进行传递之时,单精度浮点数可以直接通过寄存器传递,而双精度浮点数需要通过存储器中的堆栈进行传递。
  • d:表示目标平台支持硬件双精度浮点指令。在此架构下,如果使用了浮点类型的操作,直接使用RISC-V浮点指令进行支持。当浮点数作为函数参数进行传递之时,无论单精度还是双精度浮点数都可以直接通过寄存器传递。

Step 4:使用make命令进行构建

makemake allmake newlib 命令构建使用newlib的elf-gcc

make linux 命令构建使用glibc的linux-gnu-gcc

开启-j选项可以启动多线程编译

Step 5 设置环境变量

~/.bashrc文件末尾加入以下语句来将(yourtpath)路径加入环境变量

1
export PATH=$PATH:(yourpath)

再在终端中执行以下命令更新环境变量

1
source ~/.bashrc

Step 6 检查配置

通过相应gcc的-v命令,可以得到该工具链的配置信息,例如:

1
2
3
4
5
6
7
8
$ riscv32-unknown-elf-gcc -v
Using built-in specs.
COLLECT_GCC=./riscv32-unknown-elf-gcc
COLLECT_LTO_WRAPPER=/opt/riscv/libexec/gcc/riscv32-unknown-elf/8.2.0/lto-wrapper
Target: riscv32-unknown-elf
Configured with: /tools/riscv-gnu-toolchain-1/build/../riscv-gcc/configure --target=riscv32-unknown-elf --prefix=/opt/riscv --disable-shared --disable-threads --enable-languages=c,c++ --with-system-zlib --enable-tls --with-newlib --with-sysroot=/opt/riscv/riscv32-unknown-elf --with-native-system-header-dir=/include --disable-libmudflap --disable-libssp --disable-libquadmath --disable-libgomp --disable-nls --src=../../riscv-gcc --enable-checking=yes --disable-multilib --with-abi=ilp32 --with-arch=rv32imc 'CFLAGS_FOR_TARGET=-Os -mcmodel=medlow' 'CXXFLAGS_FOR_TARGET=-Os -mcmodel=medlow'
Thread model: single
gcc version 8.2.0 (GCC)

可以看出

1
2
3
4
5
6
--target=riscv32-unknown-elf: 指定工具为riscv32-unknow-elf
--prefix=/opt/riscv32: 指定工具生成的目录
--enable-languages=c,c++: 支持c,c++语言
--with-newlib: c运行库使用newlib
--with-abi=ilp32: 工具链支持的abi方式是ilp64
--with-arch=rv32imc: 工具链支持的riscv架构是 rv64imc

常用配置下RISCV工具链配置与编译

  1. riscv32-unknown-elf-gcc

    1
    2
    ./configure --prefix=/opt/riscv32 --with-arch=rv32imc --with-abi=lp32
    make

    编译完成后,在/opt/riscv32/bin目录下,有riscv32-unknown-elf-gcc的所有工具。

  2. riscv64-unknown-elf-gcc

    1
    2
    ./configure --prefix=/opt/riscv64 --with-arch=rv64imc --with-abi=lp64
    make

    编译完成后,在/opt/riscv64/bin目录下,有riscv64-unknown-elf-gcc的所有工具。

  3. riscv32-unknown-linux-gnu-gcc

    1
    2
    ./configure --prefix=/opt/riscv32-linux --with-arch=rv32imc --with-abi=ilp32 --enable-linux
    make linux

    编译完成后,在/opt/riscv32-linux/bin目录下,有riscv32-unknown-linux-gnu-gcc的所有工具。

  4. riscv64-unknown-linux-gnu-gcc

    1
    2
    ./configure --prefix=/opt/riscv64-linux --with-arch=rv64imafdc --with-abi=lp64 --enable-linux
    make linux

    编译完成后,在/opt/riscv64-linux/bin目录下,有riscv64-unknown-linux-gnu-*的所有工具。

构建默认riscv工具链的全部命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sudo apt-get install git autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf patchutils bc libexpat-dev libglib2.0-dev ninja-build zlib1g-dev pkg-config libboost-all-dev libtool libssl-dev libpixman-1-dev libpython-dev virtualenv libmount-dev libsdl2-dev
git clone https://gitee.com/mirrors/riscv-gnu-toolchain

cd riscv-gnu-toolchain

git clone -b riscv-gcc-10.2.0 https://gitee.com/mirrors/riscv-gcc

git clone https://gitee.com/mirrors/riscv-dejagnu

git clone -b riscv-glibc-2.29 https://gitee.com/mirrors/riscv-glibc

git clone https://gitee.com/mirrors/riscv-newlib

git clone -b riscv-binutils-2.35 https://gitee.com/mirrors/riscv-binutils-gdb riscv-binutils

git clone -b fsf-gdb-10.1-with-sim https://gitee.com/mirrors/riscv-binutils-gdb riscv-gdb

./configure --prefix=/opt/riscv

make linux -j4

参考博客

riscv-gnu-toolchain 交叉编译器如何构建? - 知乎 (zhihu.com)https://blog.csdn.net/u014558361/article/details/135372254)

riscv-gnu-toolchain工具链-从下载到运行_riscv toolchain-CSDN博客

参考视频

20201019_RISCV-GNU-Toolchain_陈嘉炜_哔哩哔哩_bilibili

一、论文总结

二、摘要

为了支持早期的Chiplets系统的设计空间探索,提出了一种基于gem5、snipe、gpgpu-sim等开源模拟器的Chiplets架构模拟方法。

并开源在Github上 https://github.com/FCAS-SCUT/chiplet_simulators

三、背景&目前待解决的问题

Chiplet是后摩尔时代一种很有前途的设计模式,但针对Chiplet的体系结构研究缺乏可靠的模拟器。

1. Chiplets微架构的设计空间比SoC要大得多,因此需要探索的设计更多

主要包括核的组织方式(128核系统可以分为32cores * 4 chiplets、16cores * 8 chiplets等)、互联的拓扑结构内存模型

2. 现有开源的模拟器无法直接用于chiplets系统的模拟,因为以下两个原因:

  • 没有精确的Chiplet间互联模型。现有开源模拟器(如gem5、sniper、Graphite、gpgpu-sim)都是纯网络模拟器(network-only simulator),缺乏详细准确的中介层互连延迟和功率模型{❓意思是仅能够精确模拟chiplet内部多核的互联,对chiplet间的互联模拟不精确吗❓}。

  • 无法进行大规模并行模拟。Multi-Chiplets系统一般具有大量的核,这样的系统模拟起来会很耗时,因此需要通过大规模的并行来加速模拟。虽然Graphite和sniper支持并行模拟,但并不支持精确的互联建模。

阅读全文 »

一、什么是GCC?

GCC(GNU Compiler Collection)即GNU编译器套件,属于一种编程语言编译器。其原名也为GCC(GNU C Compiler),虽然缩写一样但是仅可编译C语言,后来经过发展才变成支持编译多语言。GCC的初衷是为GNU操作系统专门编写的一款编译器,原本的GNU是专用于编译C代码,现如今已扩展为可以编译C、C++、Java、Objective-C等多种编程语言的编译器集合了。

二、GCC、gcc、g++三者有何关系?

gcc(GUN C Compiler)是GCC中的c编译器,而**g++**(GUN C++ Compiler)是GCC中的c++编译器。
gcc和g++两者都可以编译c和cpp文件,但存在差异。

  • gcc在编译cpp时语法按照c来编译但默认不能链接到c++的库(gcc默认链接c库,g++默认链接c++库)。

  • g++编译.c和.cpp文件都统一按cpp的语法规则来编译。

    一般编译c用gcc,**编译c++用g++**。

三、GCC编译步骤

GCC广义上的编译流程可分为以下四个部分:

  • 预处理(Pre-Processing)
  • 编译(Compiling)
  • 汇编(Assembling)
  • 链接(Linking)

四、文件类型

  • .c/.cpp:源文件
  • .h:头文件
  • .o:编译以后得到的目标文件(object)
  • .a:静态链接库,可看作若干个目标文件的集合
  • .so:动态链接库(共享库)
  • .d:源文件的依赖关系的完整规则

五、gcc 参数

浅显易懂的GCC使用教程——初级篇_gcc -ddebug-CSDN博客

【精选】gcc的基本使用-CSDN博客

GCC 编译 C(C++)静态链接库(gcc -L、gcc -l)和动态链接库(gcc -fPIC -shared)的创建和使用_c++ 链接 -l-CSDN博客

gcc -I -L -l区别 - 隔壁王叔叔a - 博客园 (cnblogs.com)

Checkpoints

官网介绍gem5: Checkpoints

检查点相当于gem5模拟系统的快照。通常来说,创建一个全系统模拟需要大量的时间,但为这个模拟系统创建了检查点之后,可以在下次启动时将模拟系统快速回复至检查点状态,从而节省系统启动时间。

一旦创建了checkpoint,gem5会在输出目录中增加一个cpt目录(cpt.TICKNUMBER,其中TICKNUMBER为创建此检查点时的Tick值),该目录存储checkpoint相关信息。

1. 创建检查点

有三种创建检查点的方式:

  • 启动模拟器环境后,在模拟器终端执行m5 checkpoint命令,也可以将其包含在运行脚本中。
  • 专门有一个伪指令用于创建检查点,例如可以在应用中创建检查点(还不熟悉)
  • python配置脚本(fs.py、ruby_fs.py)中通过命令行参数设置检查点。–take-checkpoints选项可以定期储存检查点,–checkpoint-at-end可以在模拟结束创建检查点

2. 恢复检查点

检查点恢复需要在启动系统模拟时设置几个命令行参数

1
2
3
build/X86/gem5.opt -d 指定输出目录 configs/example/fs.py --num-cpus=2 -r 1 --checkpoint-dir=checkpoint目录在指定的输出目录 --restore-with-cpu=O3CPU --cpu-type=O3CPU

build/X86/gem5.opt configs/example/fs.py --num-cpus=2 -r 1 --checkpoint-dir=m5out
  • –checkpoint-dir:用于指定使用的checkpoint的cpt文件夹所在路径
  • -r:用于指定使用的checkpoint的序号
  • –restore-with-cpu用于指定恢复时CPU的类型

启动系统模拟后,再通过m5term接入模拟系统,然后很快就会进入到命令行了。

m5

在使用m5时首先要用Scons编译

修改镜像文件

在全系统模拟中,运行程序一般比较慢,特别是一些比较大的benchmark,如果在全系统模拟中编译会极慢,因此需要将benchmark在宿主机编译完之后,直接放在镜像文件中,这样就可以开启模拟后直接运行benchmark了。

然而,镜像文件不可以像文件一样直接操作,必须进行磁盘挂载。在 Linux 中,挂载磁盘是将新的磁盘设备连接到文件系统的过程,使得该磁盘可用于存储和访问文件。简单来说,就是将镜像文件挂载到一个文件夹中,再像文件一样直接操作。

首先,创建一个文件夹作为挂载点。在disks文件夹中新建文件夹./mnt

1
mkdir ./mnt

然后,使用mount命令挂载镜像文件到指定挂载点。

1
sudo mount -o loop,offset=1048576 镜像文件 ./mnt

此时,可以通过df -h命令查看磁盘设备列表,并打开./mnt文件夹可以看到镜像文件的内容。

将测试文件放入挂载点

1
sudo cp 测试文件 ./mnt

最后,取消挂载

1
sudo umount ./mnt

FS全系统模拟

一、构建X86系统

切换到gem目录下,使用Scons进行构建

1
scons ./build/X86/gem5.opt -j [NumberOfThread]

二、获取镜像文件和Linux内核文件

FS模拟会启动Linux操作系统,会模拟系统的所有组件。因此需要给系统配置相应的Linux内核以及磁盘镜像

img 文件和 vmlinux 文件是 gem5 中启动操作系统所需的两个重要文件。

  • 磁盘镜像(img 文件)储存了操作系统的文件系统和应用程序,这些文件是操作系统运行所必需的。操作系统需要文件系统来存储和组织文件,需要应用程序来实现特定功能。
  • Linux内核文件(vmlinux 文件)储存了操作系统的内核代码。内核是操作系统的核心部分,负责管理系统资源和提供基本的服务。如果没有内核,操作系统就无法正常启动和运行。

1. 自动获取脚本

官方教程中使用的img和vmlinux直接来自于gem5资源库(resource repository),直接利用Resource类(gem5: gem5-resources)下载到本地。Gem5官网提供了通过Resource自动获取img文件和vmlinux文件,并运行全系统模拟的示例脚本,脚本代码在configs/example/gem5_library/目录中。以configs/example/gem5_library/x86-parsec-benchmarks.py为例

gem5可以通过KVM对仿真进行加速,但有的CPU不支持KVM,查看你的处理器是否支持KVM。可以通过安装sudo apt install qemu-kvm并通过kvm-ok来查看

1
2
3
4
# 安装qemu-kvm
sudo apt install qemu-kvm
# 查看KVM是否安装
kvm-ok

我的处理器并不支持KVM

因此只能关闭KVM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Step1 使用requires进行检查时将kvm_required置为False
requires(
isa_required=ISA.X86,
coherence_protocol_required=CoherenceProtocol.MESI_TWO_LEVEL,
# kvm_required=True,
kvm_required=False,
)

# Step2 设置处理器时,均使用TIMING处理器
processor = SimpleSwitchableProcessor(
# starting_core_type=CPUTypes.KVM,
starting_core_type=CPUTypes.TIMING,
switch_core_type=CPUTypes.TIMING,
isa=ISA.X86,
num_cores=2,
)

这样就可以运行模拟了,使用的benchmark和size可以在该脚本的注释中查看

2.自己制作img文件

三、设置环境变量

1
2
3
4
# 修改bashrc文件以添加环境变量
vim ~/.bashrc
# 在打开的文件的尾部加入环境变量
export M5_PATH=gem5绝对路径/full-system-image

四、通过配置文件启动模拟系统

gem5提供了许多配置文件来配置不同的系统,其中可以由fs.py与命令行参数搭配快速实现不同配置的全系统模拟

fs.py的各种命令行参数可以通过fs.py -h查看

m5端

1. m5介绍

2. 生成m5以及对应的libm5.a库

要在应用程序中使用m5提供的指令,首先需要生成m5以及对应的libm5.a库

ps: 编译之前好像要确保安装clang,并保证其版本为6-10

1
2
3
4
# Step 1 切换到gem5/util/m5目录
cd util/m5
# Step 2 编译
scons build/x86/out/m5

利用libm5.a库,即可在应用程序中使用libm5.a库中的函数

编写如下测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
########hello_m5.cpp##########
#include <stdio.h>
#include "gem5/m5ops.h" //引入m5ops.h库

int main(int argc, char* argv[])
{
m5_reset_stats(0,0); //重置模拟统计数据,m5库中实现的函数

printf("Hello world!\n");

m5_dump_stats(0,0); //将模拟统计数据保存,m5库中实现的函数
return 0;
}

利用g++和库进行编译

1
2
3
4
5
6
7
8
9
10
11
12
g++ -o hello_m5 hello_m5.cpp -std=c++11 \
-Igem5绝对路径/include \
-Lgem5绝对路径/util/m5/build/x86/out -lm5

g++ -o hello_m5 hello_m5.cpp -std=c++11 \
-I$GEM5/include \
-L$GEM5/util/m5/build/x86/out -lm5

g++ -o hello_m5 hello_m5.cpp -std=c++11 \
-I$GEM5/include \
-L$GEM5/include -lm5

然后将编译出的可执行文件通过文件挂载的方式存储到img镜像文件中。

3. 启动m5端

启动m5有两种方法,一种是通过系统自带的telnet或者gem5中提供的m5term工具,推荐m5term。

(1)telnet

使用不需要额外安装或配置,直接

1
telent <host> <post>

例如

1
2
3
telnet localhost 3456
// 3456表示用于连接模拟系统的端口号,再gem5模拟中,默认的起始端口号为3456,
// 当后续需要模拟多个系统,端口号需要每次增加1

(2)m5term

使用m5前,必须先根据源码构建该工具

1
2
3
4
5
6
# Step 1 切换到gem5/util/term目录
cd util/term
# Step 2 编译
gcc -o m5term term.c
# Step 3 安装
sudo install -o root -m 555 m5term /usr/local/bin

之后,就可以通过与telnet类似的方式启动m5了

1
m5term <host> <post>
0%