intel tbb 学习笔记

tbb是Threading Building Blocks library的缩写,是一个为开发者提供并行解决方案的库.

先放个文档https://www.threadingbuildingblocks.org/intel-tbb-tutorial

再放一个代码示例:

 

编译选项为: g++ -std=c++11 parallel_for.cpp -L/home/sensetime/workspace/graph/3rdparty/tbb/lib/intel64/gcc4.7 -ltbb -o parallel_for

 

C++ 记录代码运行时间

以前用的办法太老土啦

看到一个since C++11的方法,我觉得比较优雅

 

linux 下C++ 连接mysql 数据库

资料推荐这个:MySQL C API programming tutorial

环境为ubuntu 14.04 lts

需要安装mysql 和mysql 开发包

sudo apt-get install libmysqlclient15-dev  mysql-server mysql-client

先在mysql  中建立test数据库和test表格

 

然后用如下cpp代码连接

编译:

此次从mysql中查询,发现成功插入了一条数据.

C++ STL Algotithms 学习笔记

迫于拙劣的cpp水平,这次来记录一些关于STL算法部分的内容。

参考内容是CS106L的course reader

Iterator Categories

Iterators分为以下五种:

  • Output Iterators:可以使用”++”;可以用*myItr = value,不能用value = *myItr
  • Input Iterators:可以使用”++”;可以用value = *myItr,不能用*myItr = value
  • Forward Iterators: 可以使用”++”,可以同时用value = *myItr和*myItr = value
  • Bidirectional Iterators:比起Forward Iterator 对了”–“,但是不能+或者+=
  • Random-Access Iterators:比起Bidirectional Iterators多了+和+=

Algorithm Naming Conventions

一些关于STL Algorithm的命名规则

后缀_if表示只有当满足一定条件的时候该算法才会执行一定任务。

比如:

_n表示执行一个特定的操作n次。

比如:

Reordering Algorithms

  • sort: 传入的必须是Random-Access Iterators,记得定义<函数
  • random_shuffle:传入的必须是Random-Access Iterators,作用是将一个区间内的元素打乱重排。 可以在使用之前先使用srand函数。
  • rotate:作用是循环改变容器中元素的顺序。rotate(v.begin(), v.begin() + 2, v.end());会让(0, 1, 2, 3, 4, 5)变为(2, 3, 4, 5, 0, 1)

Searching Algorithms

  • find:三个参数,前面连个迭代器表示寻找的范围,第三个参数表示要找的值。返回第一个该值所在的位置的迭代器或者返回第二个迭代器(如果没找到)
  • binary_search:需要有序;返回某个值是否在一个范围内。
  • lower_bound:需要有序;返回大于等于某值的第一个位置的迭代器。

需要注意的是,如果某个容器本身有和STL algorithm同名的成员函数(比如set的find),那么优先使用该容器的成员函数。原因是STL Algorithm需要就有普适性,不会针对特定容易优化。因此对于set来说,其成员函数的find的复杂度是logn的,而STL alogithm的find是O(n)的复杂度。

Iterator Adaptors

具有Iterator的性质,但是比Iterator更强..

比如ostream_iterator

通过copy(myVector.begin(), myVector.end(), ostream_iterator<int>(cout, ” “)); 可以直接将一个容器中的元素输出。

比如insert_iterator,对于要从一个容器拷贝元素到另一个容器,但是在编写代码时不知道源容器的元素有多少个的问题,可以很好解决?

Removal Algorithms

需要注意的是并没有真的remove,而是将”remove”的元素放在了容器后面(?),原因是STL Algorithms接受的是Iterator,而不是Container.

Other Noteworthy Algorithms

  • transform:四个参数,前两个迭代器表示要变换的范围,第三个迭代器表示结果的开始位置,第四个参数为一个函数,表示将该范围的每个元素经过该函数的处理。不要求结果和原始的数据类型相同。
  • min_element:两个迭代器表示一个范围,返回该范围中最小元素的迭代器;可以有第三个参数来自定义小于关系。max_element与之类似。
  • accumulate:template< class InputIt, class T T accumulate( InputIt first, InputIt last, T init );
  • inner_product:求内积;T inner_product( InputIt1 first1, InputIt1 last1,
    InputIt2 first2, T value );
  • distance:连个参数,表示这两个迭代器之间元素的个数。

 

 

 

C++ IO Streams 学习笔记

迫于拙劣的cpp水平,来补补以前忽略掉的cpp细节。

老规矩,先放资料。

参考资料:

A Gentle Introduction to C++ IO Streams

“Designing and implementing a general input/output facility for a
programming language is notoriously difficult”
– Bjarne Stroustrup

Stream的基本认识

说说我的理解。stream(流)可以看做输入输出的抽象。我们通过流可以忽略掉device的细节,采取同样的输入输出方式。

对于任何原生的cpp类型,都可以用stream来处理。用户自定义的类,也可以通过重载<<和>>而让stream可以处理。

 

stream大致分为inputstream和outputstream两种,分别对应的类型为std::istream和std::ostream.

stream大概有如下操作:

  •     使用适当的值类型(如stringstream的STD : : string和fstream的文件名)和适当的模式(如用于输入的IOs : : in和用于输出的IOs : : out等,具体取决于流的类型)初始化流
  • 可以通过get和put指针指定I / O应该发生的位置。根据您打开流的方式,可能已经适当地设置了位置(例如,如果使用IOs : : app打开文件,则在流的末尾设置get指针,允许附加)。

    注意:如果需要在一个stream的中间位置插入数据的话,需要手动将指针位置后面的数据移动,否则会被覆盖掉。
  • 使用<<或者>>来读或者写。

stream的错误处理

将stream当成bool来处理是比较常见的,

但是实际上有四种status:

  • good() returns true when everything is okay.
  • bad() returns true when a fatal error has occurred.
  • fail() returns true after an unsuccessful stream operation like an unexpected type of input being encountered.
  • eof() returns true when the end of file is reached.

String Streams

emm,其实string和stream好像挺像的。 区别是,string是可以随机访问的,stream是顺序访问。

输出是:

我们观察到原本句子末尾的英文句号”.”被覆盖掉了。

buffer的使用

I/O操作是相对来说比较花时间的操作,如果我们要多次写很多小文件,那会浪费大量的时间。于是我们的想法是,使用一个临时的Buffer将数据存起来,当这个buffer满了之后再去读或者写。

注意不是所有的stream都采用了这种机制,比如cerr就没有采用。

下面放一段代码来感受下buffer

 

此处flush的含义是将buffer中的内容立即输出

我们观察发现,在testBUffer中,”before loop”是在循环之后才输出的。暗示cout使用了buffer.

 

 

vim 插件 NERDTree 学习笔记

迫于要在服务器上写cpp代码,又由于各种原因,没办法把同步到本地。因此要在服务器上配置一个cpp的环境orz.

我是用vim-plug来管理插件的,只需要添加

Plug ‘scrooloose/nerdtree’, { ‘on’:  ‘NERDTreeToggle’ }  就好了。
下面记录一些会用到的快捷键:

ctrl+w类似tmux里面的功能键。

crtl+w+w: 光标自动在左右侧窗口切换

cril+w+r:调换左右侧窗口的布局位置

t 在新 Tab 中打开选中文件/书签,并跳到新 Tab
T 在新 Tab 中打开选中文件/书签,但不跳到新 Tab
gT 前一个 tab
gt 后一个 tab

gRPC学习笔记

gRPC 是 google 最新发布的开源 RPC 框架, 声称是”一个高性能,开源,将移动和HTTP/2放在首位的通用的RPC框架.”. 技术栈非常的新, 基于HTTP/2, netty4.1, proto3, 拥有非常丰富而实用的特性, 堪称新一代RPC框架的典范.

//上面这段话是我抄的,其实我之前连RPC是什么都不知道,

关于RPC,如果你和我一样根本不知道是什么,请参考这里 

我对RPC的理解就是,一层封装,使得不在同一个机器上的程序A可以一个调用另一个程序B,而不需要考虑这两台机器,以及这两个程序使用的语言的不同。

而gRPC是诸多RPC框架中比较新,也比较好用的一个。

学习gRPC需要会使用protobuf3,关于protobuf,可以参考protobuf学习笔记

官方文档 还是要给出的,虽然我没怎么看就是了orz

gRPC的安装

参考这个,从源码编译安装

如果出现

参考

Compile fails on Ubuntu 14.04 ?  发现是protobuf的锅,需要手动编译一下:

 

gRPC的使用

grpc/examples下有一些例子,自己搞搞就会写基本的了。(已经硬着头皮用gRPC写了一个项目的通信部分了orz…其实还挺容易的。但是项目的代码没办法放上来。。。所以。。直接看examples的代码就好了。

8102年了,来更新一波vim配置

现在用的vim配置还是2015年7月的时候写的。

三年过去了,vim到了8.0,很多功能也有了更多选择。因此打算来更新一波vim配置。目前还在更新过程中。。。等差不多折腾完再来记录一些信息。

 

protobuf学习笔记

Protobuff 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

之前由于要用levelDB存feature,而levelDB的key只能是string(?,反正不能是一个数组), 使用了protobuf. protobuf本身还比较easy,不过目前似乎protobuf2仍然是主流,但是由于最近在看gRPC的缘故,要使用protobuf3. 如果protobuf2没有卸载干净,绝对欲仙欲死…记录一些坑.详细一点的笔记之后补.

// protobuf3坑好多啊…语法全靠猜,也是有毒 

行吧,怪我没找到orz,生成的cpp语法部分在 这里

先放参考资料好了。一开始找到一个pdf文档,说是官方文档的翻译版…但实际上感觉,讲得很烂。直接看官方文档比较好。

其中 Language Guide (proto3) 讲了protobuf3的proto文件的语法相关。

Protocol Buffer Basics: C++ 讲了怎么从编写proto文件到在cpp中使用的一般步骤(注意此处貌似是按照protobuf2讲的)

C++ Generated Code 讲了生成的cpp代码的接口,并且强调了protobuf2和protobuf3的区别。

生成相应代码的语法为: protoc  –cpp_out=.    test.proto

编译选项为:g++ mytest.cc test.pb.cc -o test -lprotobuf

可能遇到这个问题

Undefined reference to google protobuf

解决办法是卸载掉系统自带的protobuf相关(ubuntu14.04默认还都是protbuf2,protobuf3我是从源码自己编译的)
apt-get remove libprotobuf-dev

 

如果X是单个的变量,那么语法为set_X(val)

如果X是repeated类型,语法为add_X(val)

protobuf中message的嵌套:

对于如下的.proto


使用cpp代码访问如下:

需要注意,如果我们想要修改某个class中的另一个class的单个值,需要用mutable_name()方法,而不是name()方法.参考如下例子:

Feature里嵌套了一个Single,我现在想修改某个feature中的sin,代码如下:

但是如果要修改的是某个class中另一个class的repeated的值,则要使用add_name.

参考如下例子:

 

需要注意的是生成的代码的大小写敏感问题

对于生成cpp代码来说,无论.proto文件中的变量名是Abc还是aBc还是ABC,在生成的cpp代码中都是abc…

protobuf的大小写敏感有点坑orz..

 

troubleshooting

试图从3.5降级到3.3时编译helloworld无问题,但是运行时报错

折腾了一下午。。发现其实并不是protobuf的问题。。

用gdb调试发现。。。是grpc的一个动态库中check版本挂掉了。。。

观察grpc。。。发现还是4月20号左右的版本。。。于是删掉了所有之前的grpc在/usr/local/lib下的4月的.so文件。。。

再次运行。。成功了orz….

所以这个问题其实是。。。降级grpc遇到的问题。。。

报错太有误导性了。

 

levelDB 学习笔记

大三的时候看过一点levelDB的源码,不过没有怎么用过。

最近有个需求是存人脸的feature到硬盘,似乎使用levelDB比较合适,因此来学习一下使用。

先放参考资料。

关于levelDB的语法,看这里就好了。

以及由于caffe中使用了levelDB,因此也可以参考下caffe源码。不过caffe中对levelDB的使用是又封装了一层。

具体可以参考:

 

 

 

几个文件。。。感觉比看文档更有实际意义orz

levelDB简介

Leveldb是google开源的一个高效率的K/V数据库.有如下特点:

  1. 首先,LevelDb是一个持久化存储的KV系统,和Redis这种内存型的KV系统不同,LevelDb不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。
  2. 其次,LevleDb在存储数据时,是根据记录的key值有序存储的,就是说相邻的key值在存储文件中是依次顺序存储的,而应用可以自定义key大小比较函数,LevleDb会按照用户定义的比较函数依序存储这些记录。
  3. 再次,像大多数KV系统一样,LevelDb的操作接口很简单,基本操作包括写记录,读记录以及删除记录。也支持针对多条操作的原子批量操作。
  4. 另外,LevelDb支持数据快照(snapshot)功能,使得读取操作不受写操作影响,可以在读操作过程中始终看到一致的数据。
  5. 除此外,LevelDb还支持数据压缩等操作,这对于减小存储空间以及增快IO效率都有直接的帮助。
  6. LevelDb性能非常突出,官方网站报道其随机写性能达到40万条记录每秒,而随机读性能达到6万条记录每秒。总体来说,LevelDb的写操作要大大快于读操作,而顺序读写操作则大大快于随机读写操作。

LevelDB的安装

以ubuntu14.04为例,但实际上除了路径可能不同,其他部分是系统无关的。

leveldb_github地址

然后记得切换到指定tag

可以使用git tag命令得到,然后用git checkout命令切换,我这里使用的是1.20版本

之后直接执行make

之后将头文件拷贝到系统路径下:

编译之后分别会得到out-shared和out-static两个文件夹,分别是动态库和静态库

我们进入out-shared文件夹,讲libleveldb.so*的三个文件(有两个是链接)拷贝到/usr/lib下

然后用sudo ldconfig 命令将动态库加到缓存中。

我们用如下代码测试一下:

编译选项为:

g++ mytest.cc -o mytest -lpthread -lleveldb

如果运行得到jason,表示安装成功。

 

LevelDB的使用

一些基本操作可以参考github文档

不过发现levelDB的接口似乎只支持key和value都是string类型。。

然而对于人脸提取feature,实际上需要的是string映射到float**

,偶然发现caffe中使用了levelDB,

发现它的做法是使用protobuf将数据序列化,然后再存储。

protobuf学习笔记

 

注意事项

记录一些踩坑的经历..

如果有100条数据,想要每10条存一个数据库,那么每10条执行一次DB::Open就行了…不然会报错在put那里,导致core dumped

 

 

 

caffe2 添加自定义op

记录一些一个没有之前没有接触过caffe/caffe2的人为了添加自定义的op 到caffe2需要做的工作.

首先参考caffe2 tutorial,随便跑个op来试试,不妨以比较简单的  Accumulate_op 为例子.

这个op的作用就是计算Y=X+gamma*Y, 其中X为输入,Y为输出,gamma是参数.

跑起来这个运算所需要的代码如下:

c之后我们仿照caffe2/operators/accumultate_op.h和affe2/operators/accumultate_op.cc,仿写一个我们自己的运算atest_op.h和atest_op.cc

实现的功能为Y=5*X+gamma*Y

之后我们编译整个caffe2,编译方式是运行pytorch/scripts/build_local.sh

编译成功后,需要将pytorch目录添加到PYTHONPATH中

然后运行

看是否成功

编译的时候可能出现mpi_test.cc.o: undefined reference to symbol ‘_ZN3MPI8Datatype4FreeEv  的报错。。解决办法是把CMakeList中的MPI关掉就好了。。。

以及。。。operators中的文件都不要删。。。本想删一些不相关的op来减少编译时间。。。想法是对的。。。但是似乎只删op是行不通的。。。。不如不删。。。不然会编译出现奇怪的错误!

不然会编译出现奇怪的错误!

不然会编译出现奇怪的错误!

以及。。。从github download的速度太慢了。。。干脆开了个40$/m的vps来搞。。。

编译成功后修改测试的python代码,来测试一下我们定义的op

发现确实是得到了Y=5*X+gamma*Y 的结果。。

撒花!(然而这只是最近要做的任务中最容易的一条线orz…

需要注意的是,运行bash build_local.sh脚本之后会在pytorch目录下生成build文件夹,下次编译的时候直接在build目录下执行make -j20,这样才是增量编译

编译的时候直接在build目录下执行make -j20,这样才是增量编译

编译的时候直接在build目录下执行make -j20,这样才是增量编译

不然每次执行build_local.sh…不知caffe2用了什么机制…每次要把所有文件编译一遍…简直没有人性啊…16个cpu一起编也要5分钟Orz

以及...要在自己定义的函数最后返回true…这样在运行的时候才不会报错.否则会报net error 的错误Orz….我好傻啊?

 

 

Eigen: C++开源矩阵学习笔记

接触Eigen的原因是最近在看caffe/caffe2源码,caffe2中使用了Eigen库. Eigen 是一个基于C++模板的线性代数库,直接将库下载后放在项目目录下,然后包含头文件就能使用,非常方便。对于Linux用户,只需要把头文件放到/usr/include 下即可此外,Eigen的接口清晰,稳定高效。

之后会更新一些,Eigen中我使用过的函数.

ubuntu14.04LTS 下使用方式:

然后尝试运行如下代码,直接编译即可.如果可以正常运行,表明安装完毕.

map的使用办法:

double arr[9]={1,2,3,4,5,6,7,8,9};
Map<MatrixXd> A(arr,3,3);
得到
1 4 7
2 5 8
3 6 9

以看出默认是按列优先的…
如果需要按行优先,可以修改矩阵的定义方式:
typedef Matrix<double, Dynamic, Dynamic,RowMajor>rMatrixXd;//定义矩阵行优先
double arr[9]={1,2,3,4,5,6,7,8,9};
Map A(arr,3,3);

map使用的时候,只需要指定map<>中,缺少(dynamic)的维度.
比如

得到结果

1
2
3
4

平均值

对于矩阵:

1 4 7
2 5 8
3 6 9

按行求平均值A.rowwise().mean()

得到:

4
5
6

按列求平均值 A.colwise().mean
得到
2 5 8

unaryExpr()

参数为一元函数算子,表示对每一项应用该一元算子.具体看例子

返回的结果为:
1 16 49
4 25 64
9 36 81

 

replicate

将一个对象重复多干次.

语法为A.replicate(x,y)表示将A横向扩展x次(包含本身),纵向扩展y次(包含本身),共得到x*y个

 

linux/win双系统 更新win后 grub 出现 Error: unknown filesystem 的解决办法

windows自己更新把grub更新挂了….

更新的时候要重启几次,重启一次挂一次…

讲真,windows(或者说win10?) 是我见过的最辣鸡的OS了…  自己把自己弄挂这事不是一两次了.

下面说修复办法:

先ls,得到一堆诸如(hd0,gpt7) 这种

然后选设X=第一个(x,y)形式的输出

之后

[/crayon]

然后记得要进入linux分区…..
执行:
sudo update-grub
sudo grub-install /dev/sda

总结:珍爱生命,远离辣鸡windows!!!!!

珍爱生命,远离辣鸡windows!!!!!

珍爱生命,远离辣鸡windows!!!!!