简介
Zsim模拟器是
- 一个快速的x86-64多核模拟器,它利用英特尔Pin工具包收集进程的内存访问跟踪,并在zsim模拟器中重放跟踪。
- 一种基于 PIN 的二进制插桩工具,可以在运行时对指令进行插桩,并插入自定义的函数调用,用于模拟内存子系统的行为。
- 它最初是为了评估ZCache而编写的,但后来它扩展了其功能
- zsim的主要目标是快速,简单和准确,重点是模拟内存层次结构和大型异构系统
Zsim模拟器是
awesome-shell里多看看。
rg (Fast & Good multi-platform compatibility) > ag > ack(ack-grep) 🔥
1 | # 当前文件夹下查找 dlog关键字 |
find . -name "*xxx*"
lazydocker
The default program entry function is main, but can be changed in two situations:
#define xxx main in header file to replace the name which maybe ignored by silly search bar in VSCODE.-exxx compile flag;)取决于上下文。if, while, for)、复合语句({}) 不需要分号。#define, #include):不需要分号,因为它们不是 C++ 语法层面的内容。} 不需要分号,但声明类或结构体时 } 后要加分号。总结来说,分号用来结束语句,包括声明、表达式和执行体等,但当你定义一个复合结构(如函数定义、控制语句)时,不需要分号来结束复合结构的定义。
1 | int getKthAncestor(int node, int k) { |
根据C++的作用域规则,内层的局部变量会覆盖外层的同名变量。因此,在第二行的语句中,node引用的是函数参数中的node,而不是你想要的之前定义的node。
为了避免这个问题,你可以修改代码,避免重复定义变量名。例如,可以将第二行的变量名改为newNode或其他不同的名称,以避免与函数参数名冲突。
运算符性质:
https://en.cppreference.com/w/cpp/language/types
https://en.cppreference.com/w/cpp/types/integer
1 | //返回与平台相关的数值类型的极值 |
1 | extern |
static 作⽤:控制变量的存储⽅式和作用范围(可⻅性)。
int MyClass::staticVariable = 10;当const修饰基本数据类型时,可以将其放置在类型说明符的前面或后面,效果是一样的。const关键字用于声明一个常量,即其值在声明后不可修改。
1 | const int constantValue1 = 10; // const在类型说明符前 |
当const关键字位于指针变量或引用变量的左侧时,它用于修饰指针所指向的变量,即指针指向的内容为常量。当const关键字位于指针变量或引用变量的右侧时,它用于修饰指针或引用本身,即指针或引用本身是常量。
修饰指针指向的变量, 它指向的值不能修改:
1 | int x = 5; |
修饰指针本身 ,它不能再指向别的变量,但指向(变量)的值可以修改。:
1 | const int y = 10; |
const int *const p3; //指向整形常量 的 常量指针 。它既不能再指向别的常量,指向的值也不能修改。
在C++, explicit 是一个关键字,用于修饰单参数构造函数,用于禁止隐式类型转换。
当一个构造函数被声明为 explicit 时,它指示编译器在使用该构造函数进行类型转换时只能使用显式调用,而不允许隐式的类型转换发生。
通过使用 explicit 关键字,可以防止一些意外的类型转换,提高代码的清晰性和安全性。它通常用于防止不必要的类型转换,特别是在单参数构造函数可能引起歧义或产生意外结果的情况下。
#include_next 的作用是b.cpp想使用stdlib.h, 那么在代码的目录下创建stdlib.h,并在该文件里#include_next "stdlib.h" 防止递归引用。#define PI 3.14159,在代码中将PI替换为3.14159。const:
const int MAX_VALUE = 100;,声明一个名为MAX_VALUE的常量。typedef:
typedef int Age;,为int类型创建了一个别名Age。inline:
inline int add(int a, int b) { return a + b; },声明了一个内联函数add。define主要用于宏定义,const用于声明常量,typedef用于创建类型别名,inline用于内联函数的声明。
为了避免同一个文件被include多次,C/C++中有两种方式,一种是#ifndef方式,一种是#pragma once方式。在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。
1 |
|
namespace 会影响 typedef 的作用范围,但不会直接限制 #define 宏的作用范围。
1 | //值传递 |
引用传递和指针传递的区别:
指针传递和引用传递的使用情景:
虽然理论上可以通过类似void f(bool x = true)来实现默认值。
1 | // 函数声明 |

1 | template<typename T> |
1 |
|
VA_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。
系统提供了vprintf系列格式化字符串的函数,用于编程人员封装自己的I/O函数。
1 | int vprintf / vscanf (const char * format, va_list ap); // 从标准输入/输出格式化字符串 |
使用结构体
1 | struct RowAndCol { int row;int col; }; |
在 C++ 中,左值(lvalue) 和 右值(rvalue) 是两个重要的概念,用来描述表达式的值和内存的关系。它们帮助开发者理解变量的生命周期、赋值和对象管理,特别是在现代 C++ 中引入了右值引用后,优化了移动语义和资源管理。
左值(lvalue,locatable value) 是指在内存中有明确地址、可持久存在的对象,可以对其进行赋值操作。通俗地说,左值是能够取地址的值,可以出现在赋值操作符的左边。
特点:
& 运算符)。右值(rvalue,readable value) 是没有明确地址、临时存在的对象,不能对其进行赋值操作。它们通常是字面值常量或表达式的结果。右值只能出现在赋值操作符的右边,表示一个临时对象或数据。
特点:
& 获取右值的地址)。C++11 引入了 右值引用,即通过 && 符号表示。这使得右值也能通过引用进行操作,特别是在实现移动语义(move semantics)和避免不必要的拷贝时非常有用。右值引用允许我们通过右值管理资源,避免性能上的损失。
通常,左值是表示持久存在的对象,可以通过取地址符 & 获取其地址,而右值是临时的、短暂存在的值,不能直接获取其地址。理解这两者对于编写高效的 C++ 代码和使用现代特性(如右值引用和移动语义)非常重要。
&&)是 C++11 引入的新特性,用来优化资源管理和避免不必要的拷贝操作。在C++98/03中我们只能对普通数组和POD(plain old data,简单来说就是可以用memcpy复制的对象)类型可以使用列表初始化,如下:
1 | //数组的初始化列表: |
在C++11中初始化列表被适用性被放大,可以作用于任何类型对象的初始化。如下:
1 | X x1 = X{1,2}; |
聚合类型可以进行直接列表初始化
聚合类型包括
对于一个聚合类型,使用列表初始化相当于使用std::initializer_list对其中的相同类型T的每个元素分别赋值处理,类似下面示例代码;
1 | struct CustomVec { |
⼩贺 C++ ⼋股⽂ PDF 的作者,电⼦书的内容整理于公众号「herongwei」
https://shaojiemike.notion.site/C-11-a94be53ca5a94d34b8c6972339e7538a
暂无
暂无
上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。
无
解释型语言没有严格编译汇编过程,由解释器将代码块按需要变运行边翻译给机器执行。因此解释型语言一度存在运行效率底,重复解释的问题。但是通过对解释器的优化!可以提高解释型语言的运行效率。
Python 与大多数解释型语言一样,确实是将源代码编译为一组虚拟机指令,并且 Python 解释器是针对相应的虚拟机实现的。这种中间格式被称为 “字节码”。
Python 以 .pyc 结尾的 “ 字节码(bytecode)” 文件(二进制文件),一般位于__pycache__ 的子目录中,可以避免每次运行 Python 时去重新解析源代码。
1 | python -m py_compile file.py # 生成单个pyc文件 |
pyo文件是源代码文件经过优化编译后生成的文件,是pyc文件的优化版本。编译时需要使用-O和-OO选项来生成pyo文件。在Python3.5之后,不再使用.pyo文件名,而是生成文件名类似“test.opt-n.pyc的文件。
1 | python -O -m py_compile test.py |
CPython 使用一个基于栈的虚拟机。(你可以 “推入” 一个东西到栈 “顶”,或者,从栈 “顶” 上 “弹出” 一个东西来)。
CPython 使用三种类型的栈:
运行流程区别
python的传统运行执行模式:录入的源代码转换为字节码,之后字节码在python虚拟机中运行。代码自动被编译,之后再解释成机器码在CPU中执行。
c编译器直接把c源代码编译成机器码。过程比python执行过程少了字节码生成和虚拟机执行字节码过程。所以自然比python快。

1 | list.append('Google') ## 使用 append() 添加元素 |
setup安装包的过程,请看pip package一文。
__init__.py__init__.py文件在 Python 包结构中扮演着重要角色,但是否必须存在取决于你使用的 Python 版本和具体的使用场景。
Python 2:
__init__.py 是必需的。它标志着一个目录是一个 Python 包,允许该目录中的模块被导入。Python 3:
__init__.py 不再是必需的。Python 3 支持隐式命名空间包(Implicit Namespace Packages),这意味着即使没有 __init__.py 文件,目录也可以被视为包并进行导入。__init__.py 不再是必需的,但它仍然是推荐的做法,特别是在需要执行包级别的初始化逻辑时。命名空间(namespace)可以基本理解成每个文件是一个,通过import来使用
触发 __init__.py
__init__.py 文件。如果没有这个文件,Python 会认为这个目录不是一个包,因此 import 语句会失败。__init__.py 负责初始化这个包,可以定义一些包级别的变量、函数或导入包的其他子模块。行为:
__init__.py 文件只会在第一次导入时被执行一次。如果模块已经被导入到当前的命名空间,再次 import 不会重新执行 __init__.py,除非你强制重新加载(比如用 importlib.reload())。import 的执行会触发模块的初始化,类似于 C++ 中构造函数的概念,但不是在对象级别,而是在模块级别。1 | # example/__init__.py |
1 | import example |
| 场景 | 导入方式 | 示例 |
|---|---|---|
| 导入标准库/第三方库 | 绝对导入 | import numpy as np |
| 导入项目根目录下的模块 | 绝对导入 | from my_project import config |
| 包内模块互相引用 | 相对导入 | from . import helper |
| 直接运行脚本 | 绝对导入 | python script.py |
| 作为包的一部分运行 | 相对导入或绝对导入 | python -m package.module |
在 Python 中,import 语句是否使用点号(.)取决于你使用的是 相对导入 还是 绝对导入,以及代码所处的上下文环境。以下是详细的解释:
关键点:
__init__.py)。python main.py),否则会报错:1 | ImportError: attempted relative import with no known parent package |
if __name__ == "__main__"这种写法通常出现在模块中,它的作用是控制模块的执行流程。程序结束时的清理行为(类似析构函数的操作)
在 Python 中,并没有像 C++ 那样显式的析构函数。模块或对象的清理一般通过以下方式实现:
__del__ 方法进行资源清理。这个机制类似于 C++ 的析构函数,但触发时机取决于 Python 的垃圾回收机制。1 | class MyClass: |
atexit 模块来注册一个函数,确保在程序结束时执行。示例:使用 atexit 实现模块级别的清理操作
1 | import atexit |
输出:
1 | Program is running |
atexit 模块允许你注册多个函数,它们会在解释器关闭之前按注册顺序依次执行。__init__.py 文件。这相当于模块的 “构造” 过程。__del__ 方法来管理对象的生命周期。通常情况下,当对象不再被引用时,会自动触发清理。atexit 模块来执行程序结束时的资源清理操作。你可以在模块中注册一些函数,确保在程序退出时执行清理任务。以下是 Python 和 C++ 中一些常见的运算符及其差异:
| 运算符 | 描述 | Python 示例 | C++ 示例 |
|---|---|---|---|
// |
整数除法 | a // b |
a / b (整数除法) |
% |
取模 | a % b |
a % b |
** |
幂 | a ** b |
pow(a, b) |
| 运算符 | 描述 | Python 示例 | C++ 示例 |
|---|---|---|---|
& |
按位与 | a & b |
a & b |
| ` | ` | 按位或 | `a |
^ |
按位异或 | a ^ b |
a ^ b |
~ |
按位取反 | ~a |
~a |
<< |
左移 | a << b |
a << b |
>> |
右移 | a >> b |
a >> b |
| 运算符 | 描述 | Python 示例 | C++ 示例 |
|---|---|---|---|
//= |
整数除法赋值 | a //= b |
a /= b (整数除法) |
%= |
取模赋值 | a %= b |
a %= b |
**= |
幂赋值 | a **= b |
a = pow(a, b) |
&= |
按位与赋值 | a &= b |
a &= b |
| ` | =` | 按位或赋值 | `a |
^= |
按位异或赋值 | a ^= b |
a ^= b |
<<= |
左移赋值 | a <<= b |
a <<= b |
>>= |
右移赋值 | a >>= b |
a >>= b |
| 运算符 | 描述 | Python 示例 | C++ 示例 |
|---|---|---|---|
and |
逻辑与 | a and b |
a && b |
or |
逻辑或 | a or b |
`a |
not |
逻辑非 | not a |
!a |
| 运算符 | 描述 | Python 示例 | C++ 示例 |
|---|---|---|---|
in |
成员 | a in b |
无直接等价 |
not in |
非成员 | a not in b |
无直接等价 |
| 运算符 | 描述 | Python 示例 | C++ 示例 |
|---|---|---|---|
is |
身份相同 | a is b |
无直接等价 |
is not |
身份不同 | a is not b |
无直接等价 |
@能在最小改变函数的情况下,包装新的功能。^1
1 | def use_logging(func): |
foo.__name__变成了use_logging@wraps(func)1 | def use_logging(func): |
单下划线、双下划线、头尾双下划线说明:
__foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 init() 之类的。_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。* 和 ** 分别解包可迭代对象和字典。** 用于将传入的关键字参数打包成一个字典;** 则用于将字典解包为关键字参数。python 能很轻易的
开启 Python 的调试模式:
通过设置环境变量启用 Python 的调试信息,这有助于捕获异常和详细的堆栈信息。
1 | export PYTHONMALLOC=debug |
使用 faulthandler 模块:
Python 提供了一个 faulthandler 模块,可以用来捕获段错误并打印堆栈信息。你可以在程序的开头添加以下代码来启用它:
1 | import faulthandler |
这将会在段错误发生时输出堆栈跟踪。
查看 Python 调试输出:
启动 Python 程序时,通过 faulthandler 打印堆栈信息,或通过 GDB 调试 Python 解释器。如果 Python 解释器发生崩溃,faulthandler 会帮助你定位错误。
pstack remote pid , 虽然官方没说,但是可以pip install pystack 或者 pip install pstack安装
py-spy dump –pid 831568
如果程序能正常运行,优先推荐profiling理解程序逻辑。
traceback.print_stack()
1 | from viztracer import VizTracer |
ic.format(*args)获得ic打印的文本ic.disable()and ic.enable()ic.configureOutput(prefix='Debug | ')1 | from icecream import ic |
如果你只想捕获标准错误的输出,并将其保存到日志文件,可以使用以下命令:
1
python3.8 setup.py build bdist_wheel 1>&2 | tee compile.log
或将 `stderr` 和 `stdout` 单独重定向:
1
python3.8 setup.py build bdist_wheel 2>compile.log
定位 Python 中 setup.py 脚本运行缓慢的 热点,可以通过多种方式进行性能分析,具体步骤取决于你想了解的性能细节。以下是几种常见的方法来定位性能瓶颈。
cProfile 进行性能分析cProfile 是 Python 标准库中用于进行性能分析的工具。你可以用它来跟踪 setup.py 执行时的函数调用并找到性能瓶颈。
cProfile + snakeviz + gprof2dot
1 | ./gprof2dot.py -f pstats Diff.status | dot -Tpng -o ./output/Diff.png |
1.1 使用 cProfile 分析 setup.py
你可以通过 cProfile 运行 setup.py 并生成分析报告:
1 | python -m cProfile -o setup.prof setup.py install |
这将运行 setup.py 并将性能分析结果保存到 setup.prof 文件中。
1.2 可视化分析报告
使用 pstats 或者第三方工具 snakeviz 来分析 setup.prof:
使用 pstats 来查看分析结果:
1 | python -m pstats setup.prof |
然后,你可以在 pstats 交互式界面中输入命令,比如:
sort cumtime 按总耗时排序。stats 查看函数调用的分析结果。安装 snakeviz 来生成Web图形化报告:
1 | pip install snakeviz |
运行 snakeviz 来可视化分析结果:
1 | snakeviz setup.prof # deploy to 127.0.0.1:8080 |
这样可以生成一个图形化的界面,显示每个函数的执行时间以及调用关系,让你更直观地看到性能瓶颈。
使用 gprof2dot 生成调用关系图片:
安装 gprof2dot 工具:pip install gprof2dot
使用 gprof2dot 将 cProfile 生成的 output.prof 转换为 .dot 文件:gprof2dot -f pstats output.prof | dot -Tsvg -o output.svg
这里的 -f pstats 表示输入的格式是 cProfile 生成的 pstats 文件。这个命令会将结果转换为 SVG 格式的火焰图,保存为 output.svg。
打开生成的 SVG 文件,查看火焰图。
生成火焰图: flameprof
python flameprof.py input.prof > output.svg生成火焰图(有详细文件路径): flamegraph
flameprof --format=log requests.prof | xxx_path/flamegraph.pl > requests-flamegraph.svgline_profiler 进行逐行性能分析如果你想深入了解 setup.py 的某个函数或一组函数的逐行性能,可以使用 line_profiler 工具来分析代码的逐行执行时间。
3.1 安装 line_profiler
1 | pip install line_profiler |
3.2 添加装饰器
首先,在 setup.py 中找到你想要分析的函数,添加 @profile 装饰器(在 line_profiler 中的分析模式下使用):
1 |
|
3.3 运行 line_profiler
你可以使用 kernprof.py 来运行 setup.py 并生成逐行性能报告:
1 | kernprof -l -v setup.py install |
这将运行 setup.py 并生成一份逐行性能分析报告,显示每一行代码的耗时。
Py-Spy 进行实时性能分析(推荐!!!)Py-Spy 是一个 Python 的取样分析器,它可以在不修改代码的情况下对 Python 程序进行性能分析,并生成实时的性能报告。
4.1 安装 Py-Spy
1 | pip install py-spy |
4.2 运行 Py-Spy 对 setup.py 进行分析
你可以在执行 setup.py 的同时运行 Py-Spy 进行取样分析:
1 | py-spy top -- python setup.py install |
这会生成一个实时的报告,类似于 top 命令,显示当前正在运行的 Python 函数以及其消耗的 CPU 时间。
4.3 生成火焰图
如果你希望生成一个更直观的火焰图,可以使用 py-spy 生成火焰图文件:
1 | py-spy record -o profile.svg -- python setup.py install |
然后你可以打开 profile.svg 文件,查看一个交互式的火焰图,清晰展示函数调用的时间分布。
strace 分析系统调用如果 setup.py 涉及大量的 I/O 操作(比如读写文件或安装依赖包),可能是这些操作导致了性能瓶颈。你可以使用 strace 来分析 setup.py 的系统调用,找到 I/O 操作的瓶颈。
1 | strace -tt -T -o strace.log python setup.py install |
-tt 选项会显示每个系统调用的时间戳。-T 会显示每个系统调用耗时。-o 将结果输出到 strace.log 文件中。通过查看 strace.log,你可以找出系统调用中哪些操作耗时过长。
cProfile 或 Py-Spy 进行函数级别的性能分析,找出执行慢的函数。line_profiler 来分析慢的部分。strace 来检查系统调用。time 在脚本中插入计时代码,快速定位长时间的执行步骤。这些工具可以帮助你定位和修复 setup.py 运行缓慢的热点。
函数的单元测试
1 | python3 -m venv name |
任意变量使用pickle
1 | # 使用二进制 |
可以序列化的使用json
1 | import json |
多个变量
1 | # 将多个变量组织成字典或列表 |
其余cmake有的, Scons 也有。
Sconstruct python file as compile entryadd option for scons command
1 | AddOption('--buildDir', |
add sub scons config file and build result path using variant_dir
1 | env.SConscript("src/SConscript", variant_dir=buildDir, exports= {'env' : env.Clone()}) |
achive debug mode
using scons debug=1 command.
1 | env = Environment() |
Define the Build Environment:
In the SConstruct file, define the build environment by creating an Environment object. You can specify compiler options, flags, include paths, library paths, and other build settings within this object.
1 | env = Environment(CXX='g++', CCFLAGS=['-O2', '-Wall'], CPPPATH=['include'], LIBPATH=['lib']) |
Specify Source Files and Targets:
Define the source files for your C++ program and specify the target(s) you want to build using the Program() function.
1 | source_files = ['main.cpp', 'util.cpp', 'other.cpp'] |
In this example, main.cpp, util.cpp, and other.cpp are the source files, and my_program is the name of the target executable.
static or dynamic lib
1 | # static |
allSrcs, ".git/index", or "SConstruct") change.1 | env.Command( |
1 | scons -c # Clean |
TODO: multipim how to add a singel head file during compilation process.
暂无
暂无
上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。
根据教程
/etc:是 Etcetera(等等) 的缩写,这个目录用来存放所有的系统管理所需要的配置文件和子目录。/lib:是 Library(库) 的缩写这个目录里存放着系统最基本的动态连接共享库,其作用类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库。/opt:是 optional(可选) 的缩写,这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE数据库则就可以放到这个目录下。默认是空的。/usr:是 unix shared resources(共享资源) 的缩写,这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于 windows 下的 program files 目录。It’s install for all user./var:是 variable(变量) 的缩写,这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件。TODO: during the application install, which locations those app used?
I guess it’s usr/bin or /include , opt and /lib
暂无
暂无
上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。
无
工作外的内容聚焦于几个方面:
淡而不厌,简而文,温而理,知远之近,知风之自,知微之显,可与人德矣。
华为实习部门的都是手握A会的博士大佬。本人望尘莫及,我会狠狠吸收的。
体系结构量化分析方法,重点就在于量化分析开销,比较然后进行tradeoff。当前前提是你要有基本的相关概念。
具体知识来源的优先级,或者说如何使用搜索引擎:
在理解概念,量化了具体场景的数值后,就可以开心进行tradeoff了。
注意项目的可读性和可拓展性一般与性能是不兼容的。这取决于项目的checkpoint/middleValue的保存,在性能优化时往往会消除中间变量。这样会导致代码的可读性和可拓展性下降。
困难的定义可以基于以下几个要素进行评估:
上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。
无