我的站点

一个系统软件工程师的随手涂鸦

Author: nanxiao (Page 2 of 71)

2017年3月总结

工作方面:
这个月的工作主要就是把老项目通信框架的代码移植到新项目上,同时修改一些核心逻辑的代码。原本以为3月份能完成,结果人算不如天算,还是在最后一天发现了一些问题,看来未来两周还得继续弄了。另外一个收获就是就是对NTLHElibHEAT这三个开源项目有了更好的理解,也贡献了一些有实际意义的patch

个人项目:
写了一个C/C++项目的通用Makefile模板:generic-c-c-plus-plus-makefile

技术方面:
开始学习Rust语言,由于这月工作比较忙,有时周末时间都要被工作占据,所以掌握的并不是很好,可以说还没有入门。

这个月看的数学相关视频:
Number Theory(基本学完,剩了一点小尾巴);
Vectors and spaces(学了一半)。

 

这月看过的技术视频:

Vectors in C++

CppCon 2016: Dan Higgins “Using STL containers efficiently”

CppCon 2016: Honggyu Kim “uftrace: A function graph tracer for C/C++ userspace programs”

C++ Weekly – Ep 52 – C++ To C Compilation

Introduction to Memory Management in Linux by Alan Ott

2013 Day2P18 LoB: ELF Intro

Linux 4.x Tracing: Performance Analysis with bcc/BPF (eBPF)

Linux Talk | Linux Memory Management

查看特定进程内存使用信息 [LinuxCast IT播客]

time和/usr/bin/time

当我在bash中敲入time命令时,运行的其实是bash内置的time命令:

$ time

real    0m0.000s
user    0m0.000s
sys     0m0.000s
$ type time
time is a shell keyword

这个time命令有一个-p选项,表示以posix格式输出:

$ time -p
real 0.00
user 0.00
sys 0.00

除此以外,还有一个time命令。不过我当前的机器并没有安装这个程序:

$ which time
which: no time in (/home/xiaonan/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/cuda/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl)

安装一下,对比bash内置的time命令:

$ sudo pacman -S time
$ type time
time is a shell keyword
$ which time
/usr/bin/time

单独运行“/usr/bin/time -p”,只会输出命令的帮助选项:

$ /usr/bin/time -p
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--help] command [arg...]

需要加上具体的需要度量时间的命令:

$ /usr/bin/time -p echo

real 0.00
user 0.00
sys 0.00

此外也可以给出命令执行的详细信息:

$ /usr/bin/time -v echo

    Command being timed: "echo"
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 0%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 1536
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 70
    Voluntary context switches: 1
    Involuntary context switches: 1
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

参考资料:
/usr/bin/time: not the command you think you know

2017年2月总结

技术方面:
(a)GPU编程。参加了公司组织的培训,同时自己学习了这套教程
(b)学习Abstract Algebra
(c)学习HElib和C++;
(d)写了个lscuda小工具;
(e)写了两篇Unix微信公众号文章;
(f)看了一些linux.conf.au 2017 – Hobart, Tasmania的视频,当然没全看。

业余活动:
(a)从上个月开始看太平天国,这个月看完了。

Linux系统查看可用内存

http://www.linuxatemyram.com/提到使用free命令查看Linux系统使用内存时,used一项会把当前cache的大小也会加进去,这样会造成free这一栏显示的内存特别少:

$ free -m
               total        used        free      shared  buff/cache   available
Mem:           1504        1491          13           0         855      869
Swap:          2047           6        2041

可是实际上,cache根据应用程序的需要是可以回收利用的,因此free这一栏并不能真实地表现有多少“可以使用”的内存。实际系统可用内存应该以available数据为准。

linuxatemyram所提到的free命令也许是比较老的版本,我尝试了RHEL 7.2Ubuntu 16.04Arch Linux3Linux发行版,均没有出现used包含cache的情况:

$ free -m
              total        used        free      shared  buff/cache   available
Mem:          64325       47437        3150        1860       13737       14373

另外,从man free命令中也可以得到,目前计算used的值是要减掉freebuff/cache的:

used Used memory (calculated as total – free – buffers – cache)

可以使用-w命令行选项得到buffcache各自使用的数量:

$ free -wm
              total        used        free      shared     buffers       cache   available
Mem:          64325       48287        2476        1859        1430       12131       13524

需要注意的是,free表示的是当前完全没有被程序使用的内存;而cache在有需要时,是可以被释放出来以供其它进程使用的(当然,并不是所有cache都可以释放,比如当前被用作ramfs的内存)。而available才真正表明系统目前可以提供给应用程序使用的内存。/proc/meminfo3.14内核版本开始提供MemAvailable的值;在2.6.27~3.14版本之间,是free程序自己计算available的值;早于2.6.27版本,available的值则同free一样。

参考资料:
Understanding output of free in Ubuntu 16.04
How can I get the amount of available memory portably across distributions?

HE-API项目简介

HE-API提供一个统一的接口,屏蔽了底层使用的SHE library的细节,使对加密不是很了解的人也可以轻松掌握(代码在这里)。HE-API目前只支持HElib,通过使用不同的编译选项(FXPTBINARY)来生成支持不同数据类型的库:helib.a.fxpthelib.a.binaryhelib.a.ulong。下面以testInteger函数为例,来分析如何使用:

template <unsigned long nb_tests>
int testInteger() {
  // Determine if the test should run
  #ifdef BINARY
  unsigned long run = HE::supports_bit_encryption;
  #else
  unsigned long run = HE::supports_unsigned_encryption;
  #endif

  if (!run) {
    return 0;
  }

  timing t;

  gmp_randclass prng(gmp_randinit_default);
//  prng.seed(0);
  prng.seed(time(NULL)); // To set different seeds

  void* parameters = nullptr;
  void* sk = nullptr;
  void* pk = nullptr;
  void* evk = nullptr;

  // Init
  t.start();
  HE::init(&parameters);
  t.stop("Init");

  // Keygen
  t.start();
  HE::keygen(parameters, &sk, &pk, &evk);
  t.stop("Keygen");
  // HE::serialize_sk("sk.bin", sk);
  // std::cout << "serialized?" << std::endl;

  // Random messages
  unsigned long* messages1 = new unsigned long[nb_tests];
  unsigned long* messages2 = new unsigned long[nb_tests];
  for (unsigned long i = 0; i < nb_tests; i++) {
    messages1[i] =
        mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
    messages2[i] =
        mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
  }

  // Encrypt
  void** ciphertexts1 = new void* [nb_tests];
  void** ciphertexts2 = new void* [nb_tests];
  t.start();
  for (unsigned long i = 0; i < nb_tests; i++) {
    HE::encryptInteger(pk, &(ciphertexts1[i]), messages1[i]);
    HE::encryptInteger(pk, &(ciphertexts2[i]), messages2[i]);
  }
  t.stop("Encrypt Integer", nb_tests * 2);

  // Decrypt
  unsigned long* messages1_decrypted = new unsigned long[nb_tests];
  unsigned long* messages2_decrypted = new unsigned long[nb_tests];
  t.start();
  for (unsigned long i = 0; i < nb_tests; i++) {
    HE::decryptInteger(sk, pk, ciphertexts1[i], &(messages1_decrypted[i]));
    HE::decryptInteger(sk, pk, ciphertexts2[i], &(messages2_decrypted[i]));
  }
  t.stop("Decrypt Integer", nb_tests * 2);

  // Correctness of decryption
  for (unsigned long i = 0; i < nb_tests; i++) {
    assert(messages1[i] == messages1_decrypted[i]);
    assert(messages2[i] == messages2_decrypted[i]);
  }

  // Homomorphic additions
  unsigned long* messages_added = new unsigned long[nb_tests];
  for (unsigned long i = 0; i < nb_tests; i++) {
    messages_added[i] = (messages1[i] + messages2[i]) % HE::plaintext_modulus;
  }
  void** ciphertexts_added = new void* [nb_tests];
  t.start();
  for (unsigned long i = 0; i < nb_tests; i++) {
    HE::add(pk, evk, &(ciphertexts_added[i]), ciphertexts1[i], ciphertexts2[i]);
  }
  t.stop("Homomorphic Addition", nb_tests);

  // Correctness of addition
  unsigned long* messages_added_decrypted = new unsigned long[nb_tests];
  for (unsigned long i = 0; i < nb_tests; i++) {
    HE::decryptInteger(sk, pk, ciphertexts_added[i],
                     &(messages_added_decrypted[i]));
    assert(messages_added_decrypted[i] == messages_added[i]);
  }

  // Homomorphic multiplications
  unsigned long* messages_multiplied = new unsigned long[nb_tests];
  for (unsigned long i = 0; i < nb_tests; i++) {
    messages_multiplied[i] = (messages1[i] * messages2[i]) % HE::plaintext_modulus;
  }
  void** ciphertexts_multiplied = new void* [nb_tests];
  t.start();
  for (unsigned long i = 0; i < nb_tests; i++) {
    HE::mul(pk, evk, &(ciphertexts_multiplied[i]), ciphertexts1[i],
          ciphertexts2[i]);
  }
  t.stop("Homomorphic Multiplication", nb_tests);

  // Correctness of multiplication
  unsigned long* messages_multiplied_decrypted = new unsigned long[nb_tests];
  for (unsigned long i = 0; i < nb_tests; i++) {
    HE::decryptInteger(sk, pk, ciphertexts_multiplied[i],
                     &(messages_multiplied_decrypted[i]));
    assert(messages_multiplied_decrypted[i] == messages_multiplied[i]);
  }

  delete[] messages1;
  delete[] messages2;
  delete[] messages_added;
  delete[] messages_added_decrypted;
  delete[] messages_multiplied;
  delete[] messages_multiplied_decrypted;

  for(long i=0; i< nb_tests; i++)
  {
      HE::freeup_ciphertext(pk,ciphertexts1[i]);
      HE::freeup_ciphertext(pk,ciphertexts2[i]);
      HE::freeup_ciphertext(pk,ciphertexts_added[i]);
      HE::freeup_ciphertext(pk,ciphertexts_multiplied[i]);
  }

  delete[] ciphertexts1;
  delete[] ciphertexts2;
  delete[] ciphertexts_added;
  delete[] ciphertexts_multiplied;

  HE::freeup_keys(parameters,sk,pk,evk);

  return 0;
}

(1)HE-API使用了gmp项目:
a)gmp_randclass类用来生成随机数:

......
gmp_randclass prng(gmp_randinit_default);
//  prng.seed(0);
prng.seed(time(NULL)); // To set different seeds
......
messages1[i] =
        mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();
messages2[i] =
        mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();

b)mpz_class用来表示整数。get_ui()返回mpz_class的最低位的unsigned long。以Binary为例,mpz_class(prng.get_z_range(HE::plaintext_modulus)).get_ui();随机返回01

(2)另外就是需要注意加法和乘法时的取模运算:

......
messages_added[i] = (messages1[i] + messages2[i]) % HE::plaintext_modulus;
......
messages_multiplied[i] = (messages1[i] * messages2[i]) % HE::plaintext_modulus;

仍以Binary为例,此时PLAINTEXT_MODULUS的值为2,即要对2取模。操作数是1bit,取值为01,加密结果对应的也是01

P.S.,在编译HEAT使用HElib时可能会遇到错误,具体参考这个issue

CUDA编程笔记(17)——Matrix transpose (shared memory)

An Efficient Matrix Transpose in CUDA C/C++Coalesced Transpose Via Shared Memory一节讲述如何使用shared memory高效地实现matrix transpose

__global__ void transposeCoalesced(float *odata, const float *idata)
{
  __shared__ float tile[TILE_DIM][TILE_DIM];

  int x = blockIdx.x * TILE_DIM + threadIdx.x;
  int y = blockIdx.y * TILE_DIM + threadIdx.y;
  int width = gridDim.x * TILE_DIM;

  for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
 tile[threadIdx.y+j][threadIdx.x] = idata[(y+j)*width + x];

  __syncthreads();

  x = blockIdx.y * TILE_DIM + threadIdx.x;  // transpose block offset
  y = blockIdx.x * TILE_DIM + threadIdx.y;

  for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
 odata[(y+j)*width + x] = tile[threadIdx.x][threadIdx.y + j];
}

(1)idataodata分别是表示1024X1024float元素的matrix的连续内存:

IMG_20170216_145959[1]

(2)关于blockIdxthreadIdx的取值,参考下面的图:

IMG_20170216_151045[1]

shared memory请参考下面的图:

IMG_20170216_151058[1]

(3)在下列代码中:

for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
    tile[threadIdx.y+j][threadIdx.x] = idata[(y+j)*width + x];

每一个block32X8大小,需要循环4次,把一个block内容copytile这个shared memory中。idata是按行读取的,因此是coalesced

IMG_20170216_152636[1]

(4)最难理解的在最后一部分:

x = blockIdx.y * TILE_DIM + threadIdx.x;  // transpose block offset
y = blockIdx.x * TILE_DIM + threadIdx.y;

for (int j = 0; j < TILE_DIM; j += BLOCK_ROWS)
    odata[(y+j)*width + x] = tile[threadIdx.x][threadIdx.y + j];

对比从idata读取数据和写数据到odata

......
tile[threadIdx.y+j][threadIdx.x] = idata[(y+j)*width + x];
......
odata[(y+j)*width + x] = tile[threadIdx.x][threadIdx.y + j];
......

可以看到是把tile做了transpose的数据(行变列,列变行)传给odata。而确定需要把tile放到哪里位置的代码:

x = blockIdx.y * TILE_DIM + threadIdx.x;  // transpose block offset
y = blockIdx.x * TILE_DIM + threadIdx.y;

假设blockIdx.x31blockIdx.y0threadIdx.x1threadIdx.y2。根据上述代码,计算xy

x = 0 * 32 + 1;
y = 31 * 32 + 2;

根据下面的图,可以看到是把东北角的内容copy的西南角:

IMG_20170216_155616[1]

与*NIX有关的杂志

本文介绍一些我接触过的与*nix有关的杂志。

首先要提到的就是Linux Journal(官方网址:http://www.linuxjournal.com/)。根据Wikipedia的介绍,这应该是最早的一本介绍Linux的杂志:

Linux Journal was the first magazine to be published about the Linux kernel and operating systems based on it. It was established in 1994.

不过Linux Journal现在不再发行纸质版了,只提供电子版。该杂志这段时间有一项促销活动:即截至到今年328日前,你只需花28.5美元(使用优惠码:2017ARCH可免10美元),就可以购买到从1994年到2016年杂志的电子合订版:

1

个人觉得还是很划算的,虽然有些文章已经年代久远,但是还是很有参考价值的。另外,Linux Journal也会将其文章发布到官网上供读者免费阅读。因次,是否愿意花钱买合订本或者订阅,就“仁者见仁,智者见智”了。

再说一下Linux Format(官方网址:http://www.linuxformat.com/)和Linux Voice(官方网址:https://www.linuxvoice.com/),二者都是英国出版的Linux杂志。不知是否因为Linux Voice的主创团队均出自Linux Format的缘故,二者有太多类似之处:都同时提供纸质版和电子版,都提供过刊的免费下载,等等。也许是由于版权原因,我在国内没见到过这两种杂志。在国外我阅读过纸质版,制作很精美,每期还附赠光盘。感兴趣的朋友可以下载它们提供的过刊了解一下。

以上提到的都是以Linux为主题的杂志,再介绍一个以BSD为主打内容的杂志:BSD magazine(官方网址:https://bsdmag.org/)。这是一本真正免费的杂志,订阅以后,你不需花一分钱,就会收到每一期。从这本杂志里,你可以获悉时下BSD家族的最新动态,虽然偶尔也会有Linux的内容出现。去年年底,这本杂志一度宣布要停刊了,不过目前又撤销了这个决定。我个人很希望这本杂志可以继续办下去。

最后,我很希望自己的国家能有一本中文版的Linux杂志。但是想想现在的情形,我们的时间都被其它的事物占去了,也许根本无法诞生这样一本杂志了。。。

后记:对于其它的类似杂志,比如:http://www.linux-magazine.com/。因为我没有一点了解,就不发表评论了。

git小技巧(10)——如何同original master进行rebase

original repositorymaster branch rebase的方法:
(1)

git fetch origin # Updates origin/master
git rebase origin/master # Rebases current branch onto origin/master

(2)

git pull --rebase origin master

参考资料:
How to rebase local branch with remote master

2017年1月总结

工作方面:
a)这个月是在调试中度过的:两周调试多线程bug(参考这篇文章:An example of debugging parallel program),一周调试性能问题。收获颇丰:-);
b)学习了OpenMP技术。

业余时间(技术):

a)学习了这套Linux X86_64汇编教程
b)写了3Unix公众号文章。

业余时间(读书):
Clean, Well-Lighted Sentences: A Guide to Avoiding the Most Common Errors in Grammar and Punctuation :这本书真得很不错,很薄。利用小长假时间读了一下,弄清楚很多英语语法疑问。当然一遍不一定都能记住,还需要反复阅读。

如何选择Linux发行版?

@YeimMeMeMes 在其个人社交媒体主页上贴出了一张如何选择Linux发行版的图(原图链接:https://pbs.twimg.com/media/C3PoAagWMAAe5YT.jpg:large):

C3PoAagWMAAe5YT

因为这幅图上所列举的大部分Linux发行版我都没怎么使用过,所以我没有资格对这张图是否合理发表评论,仅供读者参考。下面我仅对我曾经使用过的一些Linux发行版谈些感受:

(1)这个图上并没有出现一些Linux的商业版本,譬如,RedHatRed Hat Enterprise LinuxSuSESUSE Linux Enterprise Server,等等。我以前做过这两个Linux商业版本上的测试工作,感觉还是很稳定的。给我一个很深的印象就是在Red Hat Enterprise Linux上编译和安装最新版本的Linux内核总是非常顺利,而在其它发行版上有时会遇到一些莫名其妙的问题。从去年开始,Red Hat Enterprise Linux对开发者已经免费了(可参考这篇文章:As in beer: Red Hat offers RHEL free to developers),有兴趣的朋友可以体验一下。

(2)最近两个月,在工作中我主要使用Arch LinuxArch Linux在软件包更新方面非常及时。有时你发现当前软件包不是最新的,只要在其网站上提一个请求,很快就会有维护者响应。如果你总是希望可以使用上最新的软件版本,不妨尝试一下Arch Linux

Page 2 of 71

Powered by WordPress & Theme by Anders Norén