PTP简介

在通信网络中,许多业务的正常运行都要求网络时钟同步,即整个网络各设备之间的时间或频率差保持在合理的误差水平内。网络时钟同步包括以下两个概念:

时间同步:也叫相位同步(Phase synchronization),是指信号之间的频率和相位都保持一致,即信号之间的相位差恒为零。

频率同步(Frequency synchronization):也叫时钟同步,是指信号之间在频率或相位上保持某种严格的特定关系,信号在其对应的有效瞬间以同一平均速率出现,以保证通信网络中的所有设备都以相同的速率运行,即信号之间保持恒定的相位差。

继续阅读PTP简介

网络时钟同步协议-- NTP, PTP

这篇文章介绍一下两个时钟同步的网络协议:NTP和PTP。
这里不涉及协议的原理和具体实现(想了解的可自行Google),重点是如何搭建起这两个服务。

1. NTP及PTP简介


NTP(Network Time Protocol)是用于不同计算机之间同步时钟的网络协议。
它的设计目标是使所有的互连的机器之间的时钟与UTC时间只相差若干毫秒

目前NTP协议已经是有第4版了,如果不需要了解NTP太多细节的话,看看这个wiki页面应该就足够了。需要注意的就是它有clock strata的概念。

PTP(Precision Time Protocol)看名字就知道是一个比NTP更精确的时钟同步协议了,PTP的设计目标是使机器之间的时钟偏差在sub-microsecond范围—这是wiki页面上提到的,有其他的地方说的是偏差若干微秒,本文搭建的环境中测量到的偏差也在微秒级别,没有到sub-microsecond级别。在使用PTP协议时,需要了解的主要概念点就是它的master/slave机制。

接下来我们就介绍我搭建NTP和PTP环境的过程,所用到的操作系统是CentOS6.5,内核版本是3.10。其他软件的版本会在用到时提及。

2. 搭建NTP服务


配置环境:两台服务器,一台做NTP服务器,一台做NTP的客户端。同时这两台机器都未联网。
NTP服务器地址:192.168.0.11
NTP客户端地址:192.168.0.22

A. 在192.168.0.11中启动NTP服务

$ service iptables stop  // 首先把防火墙关了  
$ yum list |grep ntp     // 看下yum源中是否有ntp软件    
$ yum install -y ntp    
$ ntpd --version  
    ntpd 4.2.6p5  
$ vim /etc/ntp.conf      // 修改配置文件  
    restrict 192.168.0.11 mask 255.255.255.0 nomodify nostrap  // 限制作为局域网NTP服务器
    // 下面两句很关键。含义是如果这台NTP服务器的server地址无法访问,  
    // 则将本地时间作为NTP服务时间,这个IP地址也是固定的,不要修改  
    server 127.127.1.0  
    fudge  127.127.1.0 stratum 10   
$ ntpd -p /var/run/ntpd.pid  // 启动ntpd  
$ service ntpd start          // 第二种启动ntpd服务的方法  
// 等待5分钟  
$ ntpstat // 从这条命令应该能看到NTP时钟同步好了,正常的显示结果应该与下面类似  
    synchronised to local net at stratum 11
        time correct to within 11 ms  
        polling server every 64 s

B. 在192.168.0.22上启动NTP服务,选择192.168.0.11为NTP服务器

$ service iptables stop
$ yum install -y ntp
$ vim /etc/ntp.conf  // 添加下面这个server地址,把其他的都注释掉  
    server 192.168.0.11  
$ service ntpd start
$ netstat  // 等待若干时间应该就能够显示同步成功了

我的这两台实验机器是在同一个Rack的,结果显示差不多同步的偏差在30ms左右。
每个版本的ntpd配置文件可能有少许的差别,不过好在注释都做的不错,所以别的细节就不啰嗦了。

3. 搭建PTP服务


List of PTP implementations可以看到PTP的实现有很多很多种,可以是硬件实现的,可以是软件实现的也可以是软硬件结合实现的。本文中搭建的PTP服务是基于软件PTPd。如果没有特殊的硬件的话,这算是一种非常方便的方法了。

$ service iptables stop // 关掉防火墙  
$ yum list |grep ptp    // 检查yum源  
$ yum install -y ptpd
$ ptpd2 --version  
    ptpd2 version 2.3.0  
// 弄一个管理脚本,从serverfault找来的 :)    
// http://serverfault.com/questions/329127/ptp-time-synchronization-on-centos6-rhel
$ vim ptpd.sh  // 将PTPADRGS 改为 PTPD_EXTRA_OPTIONS  
$ chmod +x ptpd.sh 
$ vim /etc/ptpd2.conf  // 修改配置文件  
    ptpengine:preset=masterslave    // 对于master主机,不要选masteronly,具体原因请查看help  
    ptpengine:preset=slaveonly      // 对于slave主机  
    // 其他选项也可以根据需要进行调整,比如log是否开启,是否绑定CPU。这些看配置文件的注释就好了  
$ vim /etc/sysconfig/ptpd2  // 修改启动命令,主要就是指定PTPD的配置文件  
    PTPD_EXTRA_OPTIONS="-c /etc/ptpd2.conf"  
// 现在就可以使用下面三个命令来启动,查看和关闭ptpd服务了  
$ ./ptpd.sh start  
$ ./ptpd.sh status  
$ ./ptpd.sh stop

如果遇到任何问题,首先一定要看看help,使用-H选项的话还能看到非常详细的配置(虽然大多我可看不懂,不过不能不看,理解的越多,遇到的问题就会越少)。
如果log里面的信息看不懂,可以把代码下下来,一个grep搞定。

经测试,在我的机器上使用PTPD软件搭建的服务,时钟偏移的平均值能够达到5us左右。这个粒度基本能满足我们的需求了。

参考链接


Linux中的时钟准确度

本文来自戴尔软件开发高级工程师Stuart Hayes

一个关于计时的问题最近引起了我的关注。 有用户在 Dell 服务器上运行 Linux,并且发现时钟时间(Linux 所报告的)每天误差五秒以上,偏差比较明显。

我们首先想到的也许是运行 NTP,定期与真实世界同步操作系统的时钟。

但是这样的误差最初是如何产生的?

在Linux运行时,Linux 系统未使用实时时钟(real time clock - RTC) 硬件来计时。 Linux 通常在启动时从RTC 读取时间,然后从该点开始,Linux 使用另一个时钟来源(系统中的另一个计时器/计数器)来计时。

自第 2.6.18 版起,Linux 的内核就使用 CPU 时间戳计数器 (TSC) 作为首选的时钟来源(假设 TSC 以恒定频率运行,以新款的 Intel 服务器 CPU为例)。 但是,尽管读取速度很快且解析度很高,TSC 却不是一个已知的频率。 当内核使启动时,它需要使用频率已知的另一个计时器,对其进行校准。 这样的校准并非天衣无缝(即使用于校准的计时器也是如此),因此把 TSC 作为时钟来源会造成时间误差。

如果减少时间误差对您非常重要,而非若干微秒的调度延迟,则最好使用频率已知的计时器,如大多数 x86 服务器上提供的 HPET(高精度事件计时器)。 借助新内核上的参数"clocksource=hpet"可实现这一目标。 HPET 计时器以已知、固定的频率运行,Linux 内核可直接从计时器读取时间。

话说回来,尽管 HPET 的精度高于 TSC,运行 NTP 以在 Linux 中实现长期的时钟精度始终是很好的想法。
上述讨论仅适用于运行于裸机的 Linux。 在虚拟机中的问题略微复杂。

原文链接


Linux 中的时钟准确度

Linux时钟精度:毫秒?微妙?纳秒?

最近被内核时钟精度弄的很是郁闷。具体情况如下:

扫盲:1秒=1000毫秒=1000000微妙=1000000000纳秒

首先:linux有一个很重要的概念——节拍,它的单位是(次/秒)。2.6内核这个值是1000,系统中用一个HZ的宏表征这个值。同时有全局的jiffies变量,表征从开机以来经过的节拍次数(这里面还有故事,后面说,先记住这个)。当然还有wall_jiffies的墙上jiffies来表示从 07-01-1970 到现在的节拍数。每个节拍里面执行一次时钟中断。就是说,它的精度是毫秒。

接着:内核中还有一个变量xtime表征系统的实际时间(墙上时间),定义如下。其中xtime.tv_sec以秒为单位,存放从Unix祖宗定的纪元时间(19700701)到现在的秒数。xtime.tv_nsec以纳秒为单位,记录从上一秒开始经过的纳秒数。就是说,它的精度是纳秒。

struct timespec xtime;

struct timespec{
    time_t tv_sec;   //秒
    long tv_nsec;    //纳秒
};

最后:linux提供一个gettimeofday的系统调用,它会返回一个timeval的结构体,定义如下。解释同上,tv_sec代表墙上时间的秒,tv_usec表示从上一秒到现在经过的微秒数。就是说,它的精度是微妙。

struct timeval{
    long tv_sec;     //秒
    long tv_usec;    //微妙
};

精彩的来了:
1. 内核中的xtime会在每个时钟中断的时候被更新一次,也就是每个节拍更新一次。你妹!!每毫秒更新一次怎么能冒出来纳秒的精度??而且,内核还有可能丢失节拍。怎么能是纳秒??
2. 各种书上说,gettimeofday系统调用是读取的xtime的值。日,为啥读出来之后精度丢了?变成微妙了?

寻寻觅觅终于理清了故事:
针对问题1:在linux启动的时候,一个节拍的时间长度还会以纳秒为单位初始化到tick_nsec中,初始化值为999848ns,坑爹啊!不到一毫秒!节拍大约为1000.15Hz。靠!实际的节拍竟然不是准确的1000!所以在每个时钟中断通过wall_jiffies去更新xtime的时候得到的就是一个以纳秒为最小单位的的值。所以!xtime的粒度应该是不到1毫秒,也就是精度是不到1毫秒。

针对问题2:gettimeday系统调用的读xtime代码部分如下:

do{
    unsigned long lost;
    seq = read_seqbegin(&xtime_lock);

    usec = timer->get_offset();    //在计时器中取从上一次时钟中断到现在的微秒数
    lost = jiffies - wall_jiffies;
    if(lost)
        usec += lost*(1000000/HZ); //HZ是节拍宏,值1000
    sec = xtime.tv_sec;
    usec += (xtime.tv_nsec/1000);  //由纳秒转为微妙

}while(read_seqretry(&xtime_lock, seq))

while部分使用了seg锁,只看中间的就好了。加了注释之后就很清晰了。由于节拍可能会丢失,所以lost是丢失的节拍数(不会很多)。至于计时器就比较麻烦了,timer可能有下面四种情况。

a. 如果cur_timer指向timer_hpet对象,该方法使用HPET定时器——Inter与Microsoft开发的高精度定时器频率至少10MHz,也就是说此时可提供真正的微妙级精度。
b. 如果cur_timer指向timer_pmtmr对象,该方法使用ACPI PMT计时器(电源管理定时器)平率大约3.58MHz,也就是说也可以提供真正的微妙级精度。
c. 如果cur_timer指向timer_tsc对象,该方法使用时间戳计数器,内置在所有8086处理器,每个CPU时钟,计数器增加一次,频率就是CPU频率,所以timer精度最高。完全可以胜任微妙级的精度。
d. 如果cur_timer指向timer_pit对象,该方法使用PIT计数器,也即是最开始提到的节拍计数,频率大概是1000Hz,此时显然不能提供精度达到微妙的时间。所以只有这种情况是假毫秒精度!

综上:如果使用gettimeofday系统调用,只要不要使用节拍计数器就可以保证达到微妙精度的时间(刨除进程上下文时间误差)。至于网上说的可以拿到纳秒精度的时间,看起来都是错的。除非通过修改内核,使用时间戳计数器实现。Over!

最后最后说一个事情:jiffies的定义的是4字节,你可能猜想它初始值是0。实际上,事实并非如此!linux中jiffies被初始化为0xfffb6c20,它是一个32位有符号数,正好等于-300 000。因此,计数器会在系统启动5分钟内溢出。这是为了使对jiffies溢出处理有缺陷的内核代码在开发阶段被发现,避免此类问题出现在稳定版本中。

参考《深入理解linux内核》

原文链接


Linux时钟精度:毫秒?微妙?纳秒?

更优雅的(不拆硬盘)拯救死翘翘了的WD MyCloud(Ubuntu 17.10)

以前WD MyCloud被捣鼓坏掉了,都是参考拯救死翘翘了的 WD MyCloud来处理的,但是这种处理方式需要拆机,非常的费力。最近看到有人发布了可以不拆机的方式修复的方法。研究了一下,非常可行,推荐使用这种方法。

下面的这些操作都是WD论坛上的一些达人通过分析WD MyCloud的源代码得到的,没有非公开的黑科技,都是一些明确公布的内容。

原理大致讲一下,在WD MyCloud主板上有一块Flash闪存,闪存里面是已经写入的bareboxWD MyCloud启动的时候会把barebox从闪存载入到内存中,并且启动barebox,而barebox启动后,会等待5S的时间,检测是否有人向自己的网卡发送内容为WD-ICMP-BEACONWD-ICMP-BEACONWD-ICMP-BEACONWD-ICMP-ICMP报文(本质就是PING),一旦检测到这个报文,就会连接这个报文的发送方的69号端口(TFTP服务器端口),获取一个名为startup.sh的脚本,并且下载完成后,执行这个脚本。因此我们就可以在这个脚本中拉取一个自己编译好的内核,然后运行这个内核,达到修改系统的目的。

继续阅读更优雅的(不拆硬盘)拯救死翘翘了的WD MyCloud(Ubuntu 17.10)

ubuntu 17.10 gnome 3桌面隐藏顶栏

1.安装gnome-tweak-tool

$ sudo apt-get install gnome-tweak-tool

2.安装hidetopbar扩展

$ sudo apt-get install gnome-shell-extension-autohidetopbar

3.重启电脑

$ sudo reboot

4.启动gnome-tweak-tool

$ gnome-tweak-tool

可以看到扩展-->Hide top bar扩展,开启即可隐藏顶栏。按键盘上的Windows图标键就会显示出来。如果还是没有隐藏,请点击设置按钮,在里面关闭智能隐藏

继续阅读ubuntu 17.10 gnome 3桌面隐藏顶栏

CNN 模型压缩与加速算法综述

CNN 模型压缩与加速算法综述

姜媚 2017-08-21 5760标签: CNN , 神经网络

导语:卷积神经网络日益增长的深度和尺寸为深度学习在移动端的部署带来了巨大的挑战,CNN模型压缩与加速成为了学术界和工业界都重点关注的研究领域之一。

前言

自从AlexNet一举夺得ILSVRC 2012 ImageNet图像分类竞赛的冠军后,卷积神经网络(CNN)的热潮便席卷了整个计算机视觉领域。CNN模型火速替代了传统人工设计(hand-crafted)特征和分类器,不仅提供了一种端到端的处理方法,还大幅度地刷新了各个图像竞赛任务的精度,更甚者超越了人眼的精度(LFW人脸识别任务)。CNN模型在不断逼近计算机视觉任务的精度极限的同时,其深度和尺寸也在成倍增长。

表1 几种经典模型的尺寸,计算量和参数数量对比

Model Model Size(MB) Million
Mult-Adds
Million
Parameters
AlexNet[1] >200 720 60
VGG16[2] >500 15300 138
GoogleNet[3] ~50 1550 6.8
Inception-v3[4] 90-100 5000 23.2

随之而来的是一个很尴尬的场景:如此巨大的模型只能在有限的平台下使用,根本无法移植到移动端和嵌入式芯片当中。就算想通过网络传输,但较高的带宽占用也让很多用户望而生畏。另一方面,大尺寸的模型也对设备功耗和运行速度带来了巨大的挑战。因此这样的模型距离实用还有一段距离。

在这样的情形下,模型小型化与加速成了亟待解决的问题。其实早期就有学者提出了一系列CNN模型压缩方法,包括权值剪值(prunning)和矩阵SVD分解等,但压缩率和效率还远不能令人满意。

近年来,关于模型小型化的算法从压缩角度上可以大致分为两类:从模型权重数值角度压缩和从网络架构角度压缩。另一方面,从兼顾计算速度方面,又可以划分为:仅压缩尺寸和压缩尺寸的同时提升速度。

本文主要讨论如下几篇代表性的文章和方法,包括SqueezeNet[5]、Deep Compression[6]、XNorNet[7]、Distilling[8]、MobileNet[9]和ShuffleNet[10],也可按照上述方法进行大致分类:

表2 几种经典压缩方法及对比

Method Compression Approach Speed Consideration
SqueezeNet architecture No
Deep Compression weights No
XNorNet weights Yes
Distilling architecture No
MobileNet architecture Yes
ShuffleNet architecture Yes

继续阅读CNN 模型压缩与加速算法综述

WD MyCloud拆硬盘恢复系统后容量部分显示0KB

捣鼓挂掉WD MyCloud之后,在参照 拯救死翘翘了的 WD My Cloud 恢复系统后,首页中的容量部分显示0KB,如下图:

解决方法为,进行一次"仅系统"的"系统出厂还原",如下图:

参考链接


MyCloud showing 0kb available, data and files cannot be accessed

让WordPress 4.9支持上传更多文件类型

WordPress对上传的文件类型是有限制的,在这里,我们以在子主题twentyfifteen-child中增加扩展名为.bz2的文件类型为例子。

首先编辑子主题的functions.php文件

$ sudo vim /var/www/wordpress/wp-content/themes/twentyfifteen-child/functions.php

在文件尾部增加如下内容:

<?php
	/*BUG Fix for after wordpress https://core.trac.wordpress.org/ticket/21299*/
	add_filter( 'wp_check_filetype_and_ext', 'upload_mimes_fix_after_47', 10, 4 );
	function upload_mimes_fix_after_47($data, $file, $filename, $mimes) {
		global $wp_version;
		if( $wp_version == '4.7' || ( (float) $wp_version < 4.7 ) ) { return $data; }
		$filetype = wp_check_filetype( $filename, $mimes );
		return [ 'ext' => $filetype['ext'], 'type' => $filetype['type'], 'proper_filename' => $data['proper_filename'] ];
	}

	/*add upload file type*/
	add_filter('upload_mimes', 'custom_upload_mimes');
	function custom_upload_mimes ( $existing_mimes=array() ) {
		$existing_mimes['bz2'] = 'application/octet-stream';
		return $existing_mimes;
	}
?>

参考链接


Ubuntu 16.04下用Python显示YUV格式的图片

YUV420p to RGB & view

from PIL import Image
import sys
from struct import *
import array

if len(sys.argv) != 4:
        print "***** Usage syntax Error!!!! *****\n"
        print "Usage:"
        print "python <script> <.yuv file yuv420p> <width&gt> <height> "
        sys.exit(1) # exit
else:
        pass

image_name = sys.argv[1]
width = int(sys.argv[2])
height = int(sys.argv[3])

y = array.array('B')
u = array.array('B')
v = array.array('B')

f_y = open(image_name, "rb")
f_uv = open(image_name, "rb")
f_uv.seek(width*height, 1)

image_out = Image.new("RGB", (width, height))
pix = image_out.load()

print "width=", width, "height=", height

for i in range(0, height/2):
    for j in range(0, width/2):
        u.append(ord(f_uv.read(1)));

for i in range(0, height/2):
    for j in range(0, width/2):
        v.append(ord(f_uv.read(1)));
for i in range(0,height):
    for j in range(0, width):
        y.append(ord(f_y.read(1)));
        #print "i=", i, "j=", j , (i*width), ((i*width) +j)
        #pix[j, i] = y[(i*width) +j], y[(i*width) +j], y[(i*width) +j]
        Y_val = y[(i*width)+j]
        U_val = u[((i/2)*(width/2))+(j/2)]
        V_val = v[((i/2)*(width/2))+(j/2)]
        B = 1.164 * (Y_val-16) + 2.018 * (U_val - 128)
        G = 1.164 * (Y_val-16) - 0.813 * (V_val - 128) - 0.391 * (U_val - 128)
        R = 1.164 * (Y_val-16) + 1.596*(V_val - 128)
        pix[j, i] = int(R), int(G), int(B)

######################################################
# B = 1.164(Y - 16)                   + 2.018(U - 128)
# G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
# R = 1.164(Y - 16) + 1.596(V - 128)
######################################################

#image_out.save("out.bmp")
image_out.show()

UYVY/YUV422 to RGB and view:

from PIL import Image
import sys
from struct import *
import array
 
if len(sys.argv) != 4:
        print "***** Usage syntax Error!!!! *****\n"
        print "Usage:"
        print "python <script> <.yuv file uyvy422> <width&gt> <height> "
        sys.exit(1) # exit
else:
        pass
 
image_name = sys.argv[1]
width = int(sys.argv[2])
height = int(sys.argv[3])
 
y = array.array('B')
u = array.array('B')
v = array.array('B')
 
f_uyvy = open(image_name, "rb")
f_uv = open(image_name, "rb")
f_uv.seek(width*height, 1)
 
image_out = Image.new("RGB", (width, height))
pix = image_out.load()
 
print "width=", width, "height=", height
 
for i in range(0,height):
    for j in range(0, width/2):
        u  = ord(f_uyvy.read(1));
        y1 = ord(f_uyvy.read(1));
        v  = ord(f_uyvy.read(1));
        y2 = ord(f_uyvy.read(1));
 
        B = 1.164 * (y1-16) + 2.018 * (u - 128)
        G = 1.164 * (y1-16) - 0.813 * (v - 128) - 0.391 * (u - 128)
        R = 1.164 * (y1-16) + 1.596*(v - 128)
        pix[j*2, i] = int(R), int(G), int(B)
 
        B = 1.164 * (y2-16) + 2.018 * (u - 128)
        G = 1.164 * (y2-16) - 0.813 * (v - 128) - 0.391 * (u - 128)
        R = 1.164 * (y2-16) + 1.596*(v - 128)
        pix[j*2+1, i] = int(R), int(G), int(B)
 
######################################################
# B = 1.164(Y - 16)                   + 2.018(U - 128)
# G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
# R = 1.164(Y - 16) + 1.596(V - 128)
######################################################
 
#image_out.save("out.bmp")
image_out.show()

原始链接


YUV to RGB : Python Imaging Library