vim gdb调试可视化

先安装gvim

1
sudo apt install vim-gtk3

再下载最新clewn

1
http://clewn.sourceforge.net

比如clewn-1.15.tar.gz

1
2
3
4
5
6
7
apt install libncurses-dev
apt install libreadline-dev
tar xaf clewn-1.15.tar.gz
cd clewn-1.15
./configure
make
make install

获取要调试程序的pid,比如98747

1
clewn -ga "-p 98747"

在原命令行中打断点再继续,当被调试程序命中断点后,gvim中会同步源码到断点处。

refer to:
http://clewn.sourceforge.net/doc.html

UE4 Shader源码编译过程

在主程序里拼成一个文件WorkerInputOnly.in后启动ShaderCompileWorker.exe进程编译shader源码。以下是调试时记录下来的命令行

D:/ue/Engine/Binaries/Win64/ShaderCompileWorker.exe "C:/Users/euhat/AppData/Local/Temp/UnrealShaderWorkingDir/A1AF8D424B2A34C30CE4378EDE6A0EFB/2/" 14492 2 WorkerInputOnly.in WorkerOutputOnly.out -communicatethroughfile  -TimeToLive=20.000000 -Multiprocess

About TLS operation

Here, TLS is the initialism of thread local storage.

pthread

1
2
3
4
5
6
#include <pthread.h>
int pthread_key_create (pthread_key_t *key, void (*destructor)(void *));
int pthread_key_delete (pthread_key_t key);
int pthread_setspecific (pthread_key_t key, const void *value);
void *pthread_getspecific (pthread_key_t key);
int pthread_once(pthread_once_t *once_control, void (*init)(void));

gcc

1
static __thread int buf[MAX_ERROR_LEN];

win32

1
2
3
4
5
6
7
8
9
10
11
12
DWORD TlsAlloc();
BOOL TlsFree(DWORD dwTlsIndex);
LPVOID TlsGetValue(DWORD dwTlsIndex);
BOOL TlsSetValue(DWORD  dwTlsIndex, LPVOID lpTlsValue);
// or
// in header,
__declspec(thread) extern size_t strdupa_len;
// and in c file, 
// as to one variable, __declspec(thread) should be write twice,
// one in prefix of prototype,
// one in prefix of definition
__declspec(thread) size_t strdupa_len;

refer to:
https://blog.csdn.net/vevenlcf/article/details/77882985
https://blog.csdn.net/linyt/article/details/51931737

c++虚继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
 
using namespace std;
 
class Base {
public:
	virtual ~Base() {}
	virtual void func() = 0;
	int base_;
};
 
class SubLeft : virtual public Base {
public:
	int subLeft_;
};
 
class SubRight : virtual public Base {
public:
	int subRight_;
};
 
class Diamond : public SubLeft, public SubRight {
public:
	void func() {}
	int diamond_;
};
 
int main()
{
	Diamond diamond;
	cout << "sizeof Base: " << sizeof(Base) << endl;
	cout << "sizeof SubLeft: " << sizeof(SubLeft) << endl;
	cout << "sizeof Diamond: " << sizeof(Diamond) << endl;
	cout << "base_ offset: " << (size_t)&diamond.base_ - (size_t)&diamond << endl;
	cout << "subLeft_ offset: " << (size_t)&diamond.subLeft_ - (size_t)&diamond << endl;
	return 1;
}

编译环境是vs2019 x64,项目属性 => C/C++ => Command Line中增加

1
/d1reportSingleClassLayoutDiamond

编译时输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1>class SubLeft	size(32):
1>	+---
1> 0	| {vbptr}
1> 8	| subLeft_
1>  	| <alignment member> (size=4)
1>	+---
1>	+--- (virtual base Base)
1>16	| {vfptr}
1>24	| base_
1>  	| <alignment member> (size=4)
1>	+---
1>class Diamond	size(56):
1>	+---
1> 0	| +--- (base class SubLeft)
1> 0	| | {vbptr}
1> 8	| | subLeft_
1>  	| | <alignment member> (size=4)
1>	| +---
1>16	| +--- (base class SubRight)
1>16	| | {vbptr}
1>24	| | subRight_
1>  	| | <alignment member> (size=4)
1>	| +---
1>32	| diamond_
1>  	| <alignment member> (size=4)
1>	+---
1>	+--- (virtual base Base)
1>40	| {vfptr}
1>48	| base_
1>  	| <alignment member> (size=4)
1>	+---
1>Diamond::$vbtable@SubLeft@:
1> 0	| 0
1> 1	| 40 (Diamondd(SubLeft+0)Base)
1>Diamond::$vbtable@SubRight@:
1> 0	| 0
1> 1	| 24 (Diamondd(SubRight+0)Base)
1>Diamond::$vftable@:
1>	| -40
1> 0	| &Diamond::{dtor}
1> 1	| &Diamond::func
1>Diamond::func this adjustor: 40
1>Diamond::{dtor} this adjustor: 40
1>Diamond::__delDtor this adjustor: 40
1>Diamond::__vecDelDtor this adjustor: 40
1>vbi:	   class  offset o.vbptr  o.vbte fVtorDisp
1>            Base      40       0       4 0

运行输出

1
2
3
4
5
sizeof Base: 16
sizeof SubLeft: 32
sizeof Diamond: 56
base_ offset: 48
subLeft_ offset: 8

refer to: https://blog.csdn.net/oracleot/article/details/5123657

c语言疑难点

1,一个星号操作并一定代表一次内存寻址操作。指针指向的内存大小是指针指向的整个内存块大小,而数组变量指向的内存大小是其某个成员所占内存大小,数组变量的大小才是整个数组占用内存大小。

1
2
3
4
5
6
7
	// in x64 mode
	int a[][2] = { 5, 4, 3, 2, 1, 6 };
	int i1 = sizeof(a);		// i1 is 24
	int i11 = sizeof(*a);		// i11 is 8
	int i2 = **(a + 1);		// i2 is 3
	int i3 = **a + 1;		// i3 is 6
	int i4 = *((int*)a + 1);	// i4 is 4

对于某类型的指针p,p+1后的地址值是增加了sizeof(*p)。
对于数组a,a+1后的地址值是增加了sizeof(*a)。

2,++操作符不参入算术式内操作符之间的优化级打架,即使++操作符在括号操作符内,是不是很反直觉?

1
2
3
4
	int a[] = { 1, 2, 3, 4, 5 };
	int *p = a;
	int j = *p++; // j is 1
	int k = *(p++); // k is 2

3,关于字节对齐

1
2
3
4
5
6
struct Diamond {
	int a1;
	char a2;
	int64_t a3;
	char a4;
};

vc2019 x64和x86下都输出

1
2
3
4
5
6
7
1>class Diamond	size(24):
1> 0	| a1
1> 4	| a2
1>  	| <alignment member> (size=3)
1> 8	| a3
1>16	| a4
1>  	| <alignment member> (size=7)
1
2
3
4
5
struct Diamond {
	char a1;
	short a2;
	char a3;
};

vc2019 x64和x86下都输出

1
2
3
4
5
6
1>class Diamond	size(6):
1> 0	| a1
1>  	| <alignment member> (size=1)
1> 2	| a2
1> 4	| a3
1>  	| <alignment member> (size=1)

vector push_back后iterator还是否有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <vector>
 
using namespace std;
 
int main()
{
    vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vector<int>::iterator it = vec.begin();
    it++;
    for (int i = 5; i < 10000; i++)
        vec.push_back(i);
    int j = *it; //这里报错
    return 1;
}

实验证明:vector push_back后原来的iterator就失效了。

1
2
3
4
5
6
7
8
    list<int> li;
    li.push_back(1);
    li.push_back(2);
    list<int>::iterator itList = li.begin();
    itList++;
    for (int i = 5; i < 10000; i++)
        li.push_back(i);
    int result = *itList;

实验证明:list push_back后原来的iterator依然有效。
如此说明,iterator中存放的是成员的内存地址,而非成员相对基地址的位移。

UE4的TMap实现原理

TMap的成员ElementSetType是TSet类型,此TSet的成员是

1
TTuple<Key, Value>

TSet类由两个动态数组组成,一个用于Hash表,一个是TSparseArray。

先说TSparseArray,其成员Data是TArray类型,即动态数组,TSparseArray的特点是通过空闲成员内部指针将空闲成员链起来,这样可方便增加删除操作,但其中的增加操作的Index是无法预先指定的。

所以TSet类又用到了一个动态数组用于Hash表,这样可以计算Hash Key找到指定Hash表项,这个表项存的是Hash桶的最后一个入桶的成员在TSparseArray数组中的Index,而其它相同Hash Key的桶成员都在最后入桶成员结构内部链起来了。

判断类的继承性

比如类定义如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <memory>
#include <iostream>
 
using namespace std;
 
class BaseA
{
public:
	int i_;
};
 
class ChildA //: public BaseA
{
public:
	int i_;
};

如下的方法只会报编译错误

1
2
3
4
5
6
7
8
9
    ChildA *a = (ChildA *)1;
    if (NULL == static_cast<BaseA*>(a))
    {
        cout << "ChildA does not inherit from BaseA 2." << endl;
    }
    else
    {
        cout << "ChildA inherits from BaseA 2." << endl;
    }

如下的方法才能编译中自动检查类的继承性并作相应处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template<class T, class = void>
struct IsFromBaseA : false_type {};
 
template<class T>
struct IsFromBaseA<T, void>
    : is_convertible<T*, BaseA*>::type {};
 
int main()
{
    if constexpr (conjunction_v<IsFromBaseA<ChildA>>)
    {
        cout << "ChildA inherits from BaseA." << endl;
    }
    else
    {
        cout << "ChildA does not inherit from BaseA." << endl;
    }
    return 1;
}

这是enable_shared_from_this实现的基础。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <memory>
 
using namespace std;
 
class Aa : public enable_shared_from_this<Aa> // 'public' is necessary.
{
public:
	shared_ptr<Aa> retThis()
	{
		return shared_from_this();
	}
};
 
int main()
{
	shared_ptr<Aa> p1 = make_shared<Aa>();
	shared_ptr<Aa> p2 = p1->retThis();
 
	p2.reset();
	p1.reset();
	return 0;
}

当p1在构造时,会检查Aa是否是enable_shared_from_this派生的类,如果是,则在enable_shared_from_this类中维护一个引用计数;如果不是enable_shared_from_this派生的,则在shared_ptr类中维护一个引用计数。

how to run EuhatOfp

create three vmware guest machines for example,
ip of no.1 guest machine is 192.168.204.33
ip of no.2 guest machine is 192.168.204.34
ip of no.3 guest machine is 192.168.204.35

setup dpdk in every machine, all script and binary are in the setup directory, refer to <5. setup dpdk> in

compile ofp over dpdk in vmware

modify test/servers.cfg

1
2
3
192.168.204.33:8061
192.168.204.34:8062
192.168.204.35:8063

for every guest machine modify self ip setting in test/ofp_netwrap.cli

1
2
3
debug 0
loglevel set debug
ifconfig fp0 192.168.204.33/24

in no.1 guest machine

1
2
cd test
./release/test 0

in no.2 guest machine

1
2
cd test
./release/test 1

in no.3 guest machine

1
2
cd test
./release/test 2

then you can check the log files in test/log directory.

how to build EuhatOfp

EuhatOfp is a library for peer to peers communication framework through user space tcp stack, now implemented in OFP over DPDK.

1. build ofp over dpdk

compile ofp over dpdk in vmware

2. build EuhatOfp

1
git clone https://github.com/euhat/EuhatOfp.git

modify the paths of dpdk, odp-dpdk and ofp in test/Makefile.

1
2
3
cd test
make clean
make