页面

分类

善用sort命令

2018年1月2日星期二, by wingfire ; 分类: 计算机技术; 0 comments

文本处理的时候难免需要排序,sort就是用来排序的工具.然而如果对sort不够熟悉,那很多时候不免觉得sort也力不从心.了解这些功能,可以让sort的能力更上一个台阶,见下表.

选项长度描述
-b--ignore-leading-blanks默认情况下,对整行进行排序,从每行的第一个字符开始。这个选项导致 sort 程序忽略 每行开头的空格,从第一个非空白字符开始排序。
-f--ignore-case让排序不区分大小写。
-n--numeric-sort基于字符串的数值来排序。使用此选项允许根据数字值执行排序,而不是字母值。
-r--reverse按相反顺序排序。结果按照降序排列,而不是升序。
-k--key=field1[,field2]对从 field1到 field2之间的字符排序,而不是整个文本行
-m--merge把每个参数看作是一个预先排好序的文件。把多个文件合并成一个排好序的文件,而没有执行额外的排序
-o--output=file把排好序的输出结果发送到文件,而不是标准输出
-t--field-separator=char定义域分隔字符。默认情况下,域由空格或制表符分隔

大部分很很好理解.-n可以按照实际数字排序,而没有的话就是按照字典排序.有了-n就可以避免11排在9前面这种尴尬了.-k对于多字段文本特别有用,比如让ls的结果按照文件大小排序,可以这么写:

ls -l /usr/bin | sort -nr -k 5

我有时还需要按照字段的特定方式排序,例如对于MM/DD/YYYY格式的日期,想按照时间排序,sort也可以做到:

Ubuntu         8.10  10/30/2008

sort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt

上面例子中的3表示第三个字段,.7表示字段的第7个字符开始,因为同时指定了-n,-k 3.7n 合起来就是第3个字段的地7个字符开始的数值.多个-k表示先按第一个k指定的字段排,在相同值的情况下再按后面的k指定字段排序.

通常sort以空白作为字段的分隔符,但是也可以用-t指定其他的分隔符.

-m可以用来合并多个已经排好序的文件到一个文件中

还有个-u参数,可以对排好序的结果做uniq,不必再调用uniq命令去重.

bash 重定向技巧

2017年12月28日星期四, by wingfire ; 分类: 计算机技术; 0 comments

重定向的顺序安排非常重要,例如:

>ls-output.txt 2>&1

重定向标准错误到文件 ls-output.txt,但是如果命令顺序改为:

2>&1 >ls-output.txt

则标准错误定向到屏幕。

现在的 bash 版本提供了第二种方法,更精简合理的方法来执行这种联合的重定向:

ls -l /bin/usr &> ls-output.txt

记一次字符串性能分析

2017年12月26日星期二, by wingfire ; 分类: 计算机技术, 代码相关; 0 comments

因为材质库增加了大量材质,不出意外地,Protein加载系统库时时间变长,也不出意外地,某产品那边表示性能很重要,必须解决.不多说了.

虽说Protein 4.0的时候,因为使用了Xirang重写实现,性能比3.0快了1~2个数量级,但是那个结果其实并不是因为Xirang够快,而是Protein 3.0实在太慢了.

Protein 4.0 其实也不快,以前虽然有过一些度量和分析,但是时间久远,,数据也没有存档.借这这一次,有机会再省视一下,发现大致有如下性能问题:

  1. 内存分配次数问题
  2. 隔离了实现的iterator
  3. 低效的已序序列的并、交、差问题
  4. Xirang.type中将copy construction分解为default construction + assignment的问题
  5. string的效率问题
  6. lexical cast的问题
  7. 二进制接口隔离导致的性能损失
  8. 访问type member和sub object的性能损失
  9. deserialize 时接口调用带来的性能损失

其中4、5和1的关系密切. 上面是做了优化后的结果了,优化之前1的情况还要糟糕得多.

因为对string做了比较细致的测量,所以这里就做一下分析和记录.别的部分有心情再说.

在一个典型应用的测试中,我记录了整个周期所有字符串的活动情况(注意,这不是某个时刻的系统快照,可能差异巨大):

  • 内容不同的字符串数量: 23916
  • 内存分配次数(除空串): 186959
  • 字符串共享计数: 1131117
  • 所有内容不同字符串长度合计: 1144861

xirang中的string设计成了immutable的,带引用计数,但是没有做小字符串的优化.因此这里的一次内存分配必然对应一次构造,实际做了186959次内存分配.

基于经验猜测,小字符串优化对性能影响是巨大的.那么在我的这个例子中,实际影响有多大呢?考虑在64位机器上实现string,那至少要能容纳一个指针,即8个字节.假设一个额外字节存储字符'\0',另一个字符用来做标记,那就是两个字符的额外开销.因此,我统计了长度分别为6,14,22,和30的情况如下表

长度类别数量内存分配次数共享计数字符总长度
6397317841118251728
14340211023550613133178
22618814124981970383360
3099631503821006513182629

百分比数据:

长度类别数量内存分配次数共享计数字符总长度
61.6617.009.890.15
1414.2258.9644.752.90
2225.8775.5572.477.28
3041.6680.4488.9815.95

从上述数据来看,采用32字节大小的string可以削减80%以上的内存分配操作,但此时共享技术削减的次数更高,达到88%.因此,单从次数上来说,再增加string的大小不太可能会更经济了.但是这么分析并没有考虑到共享方式的计数器增减对cache的毒害效应,因为共享计数器必须是原子的.但无论如何,32字节可能是一个值得考虑的上界.另外,随着string变大,额外引进的内存开销增加也是巨大的.

下面分析一下现有的string实现实际内存开销.一个string本身只含有一个指针,因此大小是8,数据部分包括计数器、hash值和size,在64位机器上大小是24,因此数据部分实际大小就是24 + N,考虑到对齐,数据部分大小将是32,40,48...这样的序列.

对长度6字节以下的字符串而言,系统实际分配的内存,数据部分大小是32,加上string本体,合计40字节.计算内存大小的公式采用:

本体大小*共享计数 + 数据大小*内存分配计数

因此内存开销分别为:

  • 6字节以下: 8*111825 + 32*31784=1911688
  • 7~14字节: 8*506131 + 40*110235=8458448
  • 15~22字节: 8*819703 + 48*141249=13337576
  • 23~30字节: 8*1006513 + 56*150382=16473496

如果为小字符串优化,当string大小取不同值时内存开销的变化:

  • 8字节: 8*111825=894600
    • 降低:1911688 - 894600 = 1017088
  • 16字节: 16*(111825 + 506131)=9887296
    • 降低: (8458448 + 1911688) - 9887296 = 482840
  • 24字节: 24*(111825 + 506131 + 819703)=34503816
    • 降低: (13337576 + 8458448 + 1911688) - 34503816 = -10796104
  • 32字节: 32*(111825 + 506131 + 819703 + 1006513)=78213504
    • 降低: (16473496+ 13337576 + 8458448 + 1911688) - 78213504 = -38032296

因为数据搜集方法的原因,这里的内存增减变化只意味着内存使用足迹的变化,不等于某个时刻的系统状态.不难看出,16字节是一个转折点.从性能上来讲,考虑到cache,复制16个字节的数据很大概率上是远远快于修改引用计数器的.因此,对于Protein来说,有充分的理由实施小字符串优化,不但能够减少58.96%的内存分配操作,同时也降低内存使用,还能避免共享计数器对cache的毒害,一举三得.

接下来从频率的角度分析.取top 1000的高频字符串:

Top N    allocate       share       chars
100:     97675      726303      1716
200:     110745     888819      3894
300:     127047     942431      5446 
400:     131816     967705      7878
600:     139471     989569      11372
800:     144086     1000744     15038
1000:    147762     1006869     18484

23916:   186959     1131117     1144861

百分比:

Top N    allocate       share       chars
100:     52.24      64.21       0.15
200:     59.23      78.58       0.34
300:     67.95      83.32       0.48 
400:     70.51      85.55       0.69
600:     74.60      87.49       0.99
800:     77.07      88.47       1.31
1000:    79.03      89.02       1.61

23916:   100        100         100

仅仅是前100条就占据了所有字符串一半以上内存分配操作和60%以上的共享计数开销,因此预置静态字符串池很可能是值得的.假设放300条数据,即便算上额外内存开销,也只需要10K左右--实际因为无需引用计数,将能降低内存占用,依赖于池的实现,这里不再详细计算了--但却能够消除60%~80%的内存分配和共享计数操作.代价是内存分配操作要换成查表操作,且查找失败的概率32.05%,这是额外惩罚.但对于共享计数操作部分,将是完全的净收益,因为不再需要修改共享计数器了.这里字符串池的查找性能将是至关重要的,完美hash表,前缀树都有可能是候选。

字符串池、小字符串优化和共享数据,这三种措施可以同时实施,只是string的实现也需要分别处理这三种状态。这可能使实现变得有点复杂,但是对于Protein和使用的系统来说,字符串的性能是及其重要的,每一点微小的提高都是值得的.

Linux 容器 (LXC)

2017年9月13日星期三, by wingfire ; 分类: 计算机技术; 0 comments

错误处理

  1. unshare: Operation not permitted

  echo 1 > /sys/fs/cgroup/cpuset/cgroup.clone_children
  echo 1 > /proc/sys/kernel/unprivileged_userns_clone
  1. WARN: could not reopen tty: Permission denied

参考 https://gist.github.com/julianlam/4e2bd91d8dedee21ca6fhttps://github.com/lxc/lxc/issues/181 TL;DR 总之,这是因为先su到root,再su -到非特权用户,在此过程中,cgroup信息有丢失导致问题。

Time Machine备份速度很慢

2017年8月28日星期一, by wingfire ; 分类: 计算机技术; 0 comments

Time Machine备份很慢,google之,发现下面的设置有效:

sudo sysctl debug.lowpri_throttle_enabled=0

备份完再改回来:

sudo sysctl debug.lowpri_throttle_enabled=1

备份过程中,可以通过 fs_usage backupd 查看文件访问详情。

previous page

下一页