分类目录归档:Linux

关于 Linux Kernel 4.15 + gcc 7.3 编译内核模块时无法找到 stdarg.h 的问题

这是一个非常奇怪的错误,出现在 Ubuntu 18.04 上,默认安装的内核版本是 4.15,gcc 是 7.3,在编译内核模块时报错:

In file included from ./include/linux/list.h:9:0,
                 from ./include/linux/module.h:9,
                 from /root/Software/newbbr/tcp_tsunami.c:59:
./include/linux/kernel.h:6:10: fatal error: stdarg.h: No such file or directory
 #include <stdarg.h>
          ^~~~~~~~~~
compilation terminated.

gcc 认为找不到 stdarg.h。看这个错误的位置,个人认为应该不是我配置的问题或者是我代码的问题,搜索了一下,也有很多在 4.15 内核上出现的同样错误。目前没有什么很好的解决方案,暂时性的方案是在编译的 Makefile 里面加一行:

ccflags-y=-I/usr/lib/gcc/x86_64-linux-gnu/7/include

如果是 gcc 8,就相应把版本改成 8 就可以了

将 Linux 上的 VSCode 改为 Consolas 字体

Linux 上的 VSCode 写起代码来总让人觉得莫名烦躁,而 Windows 上面的 VSC 就赏心悦目很多,想了很久之后终于发现是默认字体的问题。Windows 上面的 VSC 默认是 Consolas 字体,在 Ubuntu 上面大概是 Droid Sans 家族的某种版本,实在是不好看,所以换掉。

首先要在 Ubuntu 上安装 Consolas:

wget https://down.gloriousdays.pw/Fonts/Consolas.zip
unzip Consolas.zip
sudo mkdir -p /usr/share/fonts/consolas
sudo cp consola*.ttf /usr/share/fonts/consolas/
sudo chmod 644 /usr/share/fonts/consolas/consola*.ttf
cd /usr/share/fonts/consolas
sudo mkfontscale && sudo mkfontdir && sudo fc-cache -fv

这样就装好了。用 fc-list 可以看所有安装的字体。

之后在 VSC 的 preference 中修改对应的项:

"editor.fontFamily": "'Consolas', 'Droid Sans Mono', 'monospace', monospace, 'Droid Sans Fallback'"

这样就可以了

20181130 Update:

如果没有 root 权限,由于 ~/.fonts 实际上就是用户个人的字体文件夹,因此我们在 $HOME 文件夹下也可以做到同样的事情:

wget https://down.gloriousdays.pw/Fonts/Consolas.zip
unzip Consolas.zip
mkdir ~/.fonts
cp consola*.ttf ~/.fonts
cd ~/.fonts
mkfontscale
mkfontdir
fc-cache -fv ~/.fonts

之后用 fc-list 可以看到新安装的字体,在 VSCode 中也可以进行调整。

无 root 权限的服务器使用的一些记录

在没有 root 权限的服务器上安装 pip

假设有这么一台服务器,你没有 root 权限,然后预配置的 tensorflow 环境很神奇地调用不了 GPU,只有 pip2 没有 pip3,python2 python3 都试过了都没法用 GPU,pip list 也显示安装了 tensorflow-gpu,且给你用户的人信誓旦旦地告诉你我这配置没问题,但是你就是用不了 GPU,那么怎么办呢?

解决方法还是比较简单的,首先在用户态安装一个 pip(本文要装 pip3)

wget https://bootstrap.pypa.io/get-pip.py && python3 get-pip.py --user

这时候 pip3 会被安装到 ~/.local/bin 下面,如果你的 PATH 里面有这个路径的话,直接 pip3 就可以运行。

然后就很简单了,该干嘛干嘛,比如安装 virtualenv 等等,只不过这时候你安装任何 python 包的时候,要加上 –user 参数,才能安装到 $HOME 下面,例如 pip3 install virtualenv –user。

我之前提到的那台服务器呢,在装了 pip3 以后,list 一下发现根本就没有 tensorflow-gpu,只有 tensorflow;pip2 里面有,但是调用不了显卡,搞不懂 IT 究竟是怎么配置的。最后我也懒得烦了,直接 virtualenv,装一个 tensorflow-gpu,问题就解决了。

安装一个简单的 deb 包(没有 dependency 问题那种)

apt download <package>
dpkg-deb -x package_x.y.z_x86_64.deb my-private-root
#dpkg-deb -e package_x.y.z_x86_64.deb my-private-control

然后就装在了你自己的 $HOME 下面。

如果你装的是 screen,且你对 /var/run/screen/ 也没权限的话,这么干:

mkdir ~/.screen && chmod 700 ~/.screen
export SCREENDIR=$HOME/.screen

然后把对应的内容添加到 .bashrc 里面去让你每次都可用,比如说:

PATH=~/usr/bin:$PATH
export SCREENDIR=$HOME/.screen

 

Ubuntu 18.04 LTS 盒子环境的部署

本文测试环境为 Hetzner E3-1245V2 独服,系统为官方的 Ubuntu 18.04 Minimal 模板。本文需要综合上一篇盒子配置文章阅读。

写在前面

经过长期的测试,考虑到双栈 IP 的需求,Deluge / qBittorrent 需要 libtorrent 1.0.11 版本才能正常汇报双栈 IP,所以本文很多操作都为了这个目标而设。

Deluge 1.3.15 官方 PPA 仍然没有更新 18.04 对应的二进制包,所幸 Ubuntu 官方源里面就是 1.3.15,理论上可以使用。但是考虑到使用 apt 安装会导致安装官方源中自带的 libtorrent 1.1.5 的依赖,因此选择完全编译安装 libtorrent 与 Deluge。

Wine 官方源也没有增加 Ubuntu 18.04 的支持,Ubuntu 官方源中有对应的 wine64 软件包,因此选择安装该包而非 Wine 官方的版本。

E3-1245V2 有自带 Intel 集显,考虑到 X11VNC 配合 Xorg 使用可以支持完整的键盘操作(VNCserver 存在无法输入 tab、WinKey 的问题,还有 24bit 显示导致 VMware 颜色错乱的问题),本文中选择安装 X11VNC。考虑到通用性,仍应参考上一篇文章使用 VNCserver。

环境的部署

本文所有编译环境采用最新的 gcc-8.1 完成,注意 Boost 需要最高 1.65.1 版本,这个和目前 Ubuntu 源中的版本一致。

# gcc-8 Prerequisites
add-apt-repository ppa:ubuntu-toolchain-r/test
# Compiler
apt install gcc-8 g++-8 build-essential checkinstall pkg-config automake libtool git
# Libtorrent Dependency
apt install libboost-dev libboost-system-dev libboost-python-dev libboost-chrono-dev libboost-random-dev libssl-dev libgeoip-dev
# Deluge Dependency
apt install python-pip python-attr python-automat python-chardet python-click python-colorama python-constantly python-hyperlink python-incremental python-openssl python-pam python-pyasn1 python-pyasn1-modules python-serial python-service-identity python-twisted-bin python-twisted-core python-zope.interface python-twisted python-openssl python-setuptools intltool geoip-database python-notify python-pygame python-glade2 librsvg2-common xdg-utils python-mako
# qBittorrent Dependency
apt-get install qtbase5-dev qttools5-dev-tools libqt5svg5-dev

libtorrent 1.0.11 的编译

综合参考 Deluge 的文档与 qBittorrent 的文档。

git clone https://github.com/arvidn/libtorrent.git libtorrent-1.0.11
git checkout $(git tag | grep libtorrent-1_0_ | sort -t _ -n -k 3 | tail -n 1)
./autotool.sh
./configure --enable-python-binding --with-libiconv --disable-debug --enable-encryption --with-libgeoip=system CXXFLAGS=-std=c++11
make -j$(nproc)
checkinstall
ldconfig

注意 libtorrent 1_0_x 的代码需要修改才能正常地引用 Boost,毛球说 RC_1_0 分支不存在本问题,未作测试。

//修改include/libtorrent/export.hpp
//那两个hpp文件在boost/config/detail/下,而不是boost/config/下

#if !defined(BOOST_COMPILER_CONFIG) && !defined(BOOST_NO_COMPILER_CONFIG)
#  include <boost/config/detail/select_compiler_config.hpp>
#endif
#ifdef BOOST_COMPILER_CONFIG
#  include BOOST_COMPILER_CONFIG
#endif

#if !defined(BOOST_PLATFORM_CONFIG) && !defined(BOOST_NO_PLATFORM_CONFIG)
#  include <boost/config/detail/select_platform_config.hpp>
#endif
#ifdef BOOST_PLATFORM_CONFIG
#  include BOOST_PLATFORM_CONFIG
#endif

Deluge 安装

wget http://download.deluge-torrent.org/source/deluge-1.3.15.tar.gz
tar xzvf deluge*.tar.gz
python setup.py build
python setup.py install

注意这种方式安装的 Deluge 默认在 /usr/local/bin 下,而不是像 deb 安装一样在 /usr/bin。如果需要安装在 /usr/bin 下,安装时添加参数 –install-layout=deb。

其他软件的部署

add-apt-repository ppa:transmissionbt/ppa
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
dpkg --add-architecture i386 
apt install --install-recommends xorg x11vnc transmission-daemon sshfs nodejs firefox fonts-noto xfce4 wine-stable
apt install gtk3-engines-xfce xfce4-goodies xfce4-power-manager

Xorg 配置文件

位置在 /usr/share/X11/xorg.conf.d/20-intel.conf

Section "Device"
   Identifier  "Intel Graphics"
   Driver      "intel"
   Option      "AccelMethod"  "sna"
   Option      "TearFree"     "true"
EndSection

Section "Monitor"
    Identifier      "External VGA"
    Modeline        "1600x900_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -Hsync +Vsync
    Option          "PreferredMode" "1600x900_60.00"
EndSection

Section "Screen"
    Identifier    "Screen0"
    Device        "Device0"
    Monitor       "Monitor0"
    DefaultDepth  24
    SubSection "Display"
        Depth 24
        Modes "1600x900"
        Virtual 1600 900
    EndSubSection
EndSection

X11VNC 与 Xorg 的 systemd 启动脚本

# xserver.service
[Unit]
Description=Xserver
After=network-online.target

[Service]
ExecStart=/usr/bin/sudo /usr/bin/startx -- :0
Restart=always
Type=simple
RestartSec=3

[Install]
WantedBy=multi-user.target
# x11vnc.service
[Unit]
Description=X11vnc
After=network-online.target xserver.service
Wants=xserver.service

[Service]
ExecStart=/usr/bin/sudo /usr/bin/x11vnc -rfbport 25901 -rfbauth /root/.vnc/passwd  -display :0 -forever -nevershared -bg -repeat -nowf -o /root/.vnc/x11vnc.log
Restart=always
Type=forking
RestartSec=3

[Install]
WantedBy=multi-user.target

x11vnc 需要首先创建 ~/.vnc/passwd 文件,这个 VNCserver 运行的时候也会自动创建,我懒得重新建立就没研究这个,改日有空再写吧。

Xorg 默认启动的文件为 ~/.xinitrc

#!/bin/sh

# /etc/X11/xinit/xinitrc
#
# global xinitrc file, used by all X sessions started by xinit (startx)

# invoke global X session script
. /etc/X11/Xsession
exec startxfce4

参考资料

https://wiki.archlinux.org/index.php/Xinit_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

https://wiki.archlinux.org/index.php/X11vnc_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

https://blog.csdn.net/songbaiyao/article/details/72858087

https://wiki.archlinux.org/index.php/Xorg_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

https://wiki.archlinux.org/index.php/Intel_graphics_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)

https://serverfault.com/questions/174003/how-can-opengl-graphics-be-displayed-remotely-using-vnc

https://askubuntu.com/questions/537787/enable-3d-hw-acceleration-on-vmware-workstation-10-on-ubuntu-14-04

https://github.com/qbittorrent/qBittorrent/wiki/Compiling-qBittorrent-on-Debian-and-Ubuntu

https://dev.deluge-torrent.org/wiki/Installing/Source

关于近期出现的大量公网 libtorrent BT 客户端的问题

经确认,如果 IP 来源为 CN,且客户端类型汇报为 libtorrent 这个库而非其他正常客户端的 peer,既有可能是迅雷等下载软件的离线客户端。对于一部分同样表现的海外 IP 暂时未能确认,不确定是否有一些极小众的客户端表现确实如此,对于此问题,在 qBittorrent 增强版未作修改之前,建议采取 ipfilter 的方式屏蔽这些客户端。

IP Filter 来源如下:https://emulefans.com/offline-server-ip-170205/

也可以直接下载

关于 qBittorrent 编译的一些问题

您可能是开源软件的受害者!

您可能是开源软件的受害者!

您可能是开源软件的受害者!

重要的事情说三遍。

实际上这次也没做什么理论上很麻烦的事情,就是 clone 一个 qBittorrent 4.0.4.3 的源码,配合 libtorrent 1.0.11 编译一下,理论上不应该有什么问题的对吧。然而就是出问题了……

编译的过程很顺利,安装 Deluge PPA 的 libtorrent-rasterbar-dev 和一些 boost 库之后开始编译,然后到了 linking 的过程就报错了:src/base/bittorrent/private/filterparserthread.cpp:99: reference to `boost::asio::ip::address_v4::address_v4(std::array<unsigned char, 4u> const&)'

按照 GitHub Issue #6721,这个问题可能是因为 std::arrayboost::array 这两个名称的选择在 libtorrent 和 qbittorrent 里面不同,在没有使用 stdc++11 编译的时候,使用的是 boost::array,反之使用 std::array,考虑到 qbittorrent 默认需要 C++ 11,所以 libtorrent 应该使用同样的 CXXFLAGS 编译才能在 linking 的时候不报错。因此既然出现了现在这个问题,就证明 Deluge PPA 的 libtorrent 是没有使用 C++11 编译的。

之前在编译 qb 3.3.16 的时候并没有出现这个错误,可能是 qb3 不要求 C++11 的原因。

那么如果要解决这个问题,就必须从源码开始编译 libtorrent。考虑到 lt1.1.x 至今无法解决 U2 的双栈 IP 汇报问题,因此只能采用 lt1.0。

git clone https://github.com/arvidn/libtorrent.git
cd libtorrent
git checkout $(git tag | grep libtorrent-1_0_ | sort -t _ -n -k 3 | tail -n 1)
./autotool.sh
./configure --disable-debug --enable-encryption --with-libgeoip=system CXXFLAGS=-std=c++11

在编译完成之后,checkinstall 安装,然后再去编译 qb 就应该可以了。

关于 Boost 版本

Boost 版本的选择也有一些讲究,Ubuntu Package 默认的是 1.58 版本的 boost,qb 经过测试,最高只能使用 1.65.1 版本的 boost,如果想要使用新一些的版本,只能自己编译。

我在编译 1.65.1 的时候,遇到了一个以前从来没有的问题,找不要 pyconfig.h,这个文件本应该存在于 /usr/include/python 或者 python2.7 或者 python3.5 的目录下(取决于默认 Python 版本),但是我那个 Python 2 就是没有这个文件,因此将 Python 默认改为 3.5(sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.5 10)才让 boost 的编译器找到对应的 Python 头文件。如果出现这样的问题需要注意。

使用 echo -e '#include <boost/version.hpp>\nBOOST_VERSION' | gcc -x c++ -E - 这个命令可以查看当前 include 的 boost 版本。

Python 版本切换的注意点

如果安装了 Deluge,然后再切换到 Python3,可能会让 Python 找不到 Deluge 的包,然后无法运行,解决方法是修改 /usr/bin/deluged 和 /usr/bin/deluge-web 的第一行,用 python2.7 运行。或者也可以编译完 boost 以后再把默认 python 改回来。

 

Syncthing 配合 Nextcloud 搭建私有云

写在前面

首先感谢 youlun 大佬介绍了 Syncthing 这个好用的文件同步工具,一次性解决了 Nextcloud 同步残废的问题。

有人可能会问,Nextcloud 不就已经可以搭建私有云平台了吗,为什么还要借助 Syncthing 这样一个同步工具呢?如果文件量不大的话,可能这并不是什么大问题,但是由于 Nextcloud 即使是使用它的客户端,也只能通过网页方式上传,在遇到较大的文件的时候,就会遇到各种各样的限制,比如上传超时或者是文件过大不能上传等等。但是 Syncthing 就不存在这样的问题,可以顺畅地进行文件同步。那么,有没有办法让二者配合工作,即 Syncthing 负责文件同步,Nextcloud 负责网页端的界面和移动端访问的功能呢?答案是有的,而且非常可行,考虑到没有现成的教程,因此在这里记录一下。

LNMP 环境部署

WebServer 环境依然使用了 LinuxEye 的 LNMP 一键包,需要注意的问题是 PHP 选择 7.1 版本(Nextcloud 13.0.1 的依赖),以及需要通过 addon.sh 安装 fileinfo 这个 PHP 模块。

Nextcloud 安装

在部署完成环境之后,添加一个 nginx vhost,现在最新版的一键包中已经加入了 Nextcloud 的 Rewrite Rule,这个给我们的安装带来了极大的方便,再也不用去折腾那些重写规则了。

然后需要调整一下 Zend OPcache 的设置,不然在下载源码之后无法进入配置。具体步骤为在 /usr/local/php/etc/php.d/ 文件夹中找到 opcache 的 .ini 配置文件,将里面的数值按照如下的错误信息调整:

之后在官网下载 tar.bz2 的安装包,解压之后拷贝进 wwwroot,注意这里需要将所有的文件权限改为 www:www,默认一般是登录的用户,会造成无法访问,之后在 MariaDB 中创建一个数据库,在初始化的时候填进 Nextcloud 中,这一步还是比较方便的。

然后更改一下 Nextcloud 的配置,消除缓存的警告。在 <site root>/config/config.php 中添加如下字段即可:

'memcache.local' => '\OC\Memcache\Redis',
'memcache.locking' => '\OC\Memcache\Redis',
'redis' => array(
   'host' => 'localhost',
   'port' => 6379,
),

至此 Nextcloud 应该就可以正常使用了。

Syncthing 的配置

首先需要安装 Syncthing,官方文档中给出了 Ubuntu .deb 的链接,按照它配置即可。

这时候就会遇到一个问题,Syncthing 需要以 www 用户启动才能在和 Nextcloud 一同工作时避免一些权限的问题,但是 www 用户默认是 nologin 配置的,如何登陆进这个用户完成一些初始的设置是一个比较麻烦的问题。由于 www 用户无法登录,所以不能使用一般的 su <user> 来进行用户切换,以该用户的权限启动一个 bash 又不能完成完整的用户环境切换操作。在搜索之后,以一种比较 Tricky 的方法登录了进去:

su -s /bin/bash www

这条命令的意思是 override www 默认的 shell,再登录,然后就会发现你已经切换到 www 用户下了。运行 syncthing,该做什么做什么。

Nginx 反代

Syncthing 默认监听 localhost:8384 端口,那么在远端 VPS 上,如何进行配置呢?有两个方案,一个是修改监听端口,让程序监听 0.0.0.0:8384,另外一个是通过 nginx 配置一个反代。显然,第二个方案无论是在安全性,还是便利性(不用在域名后面输入端口号)上都优于第一个,所以我们就采用第二个方案。

Nginx 配置文件的关键部分如下:

server {
  listen 80;
  listen 443 ssl http2;

  if ($ssl_protocol = "") { return 301 https://$host$request_uri; }

  location / {
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header Host localhost;
          proxy_set_header X-NginX-Proxy true;
          proxy_pass http://localhost:8384;
  }
}

需要注意的一点就是 proxy header 中的 Host 字段必须改为 localhost,否则 Syncthing 发现你的访问地址不是它的监听地址,就会拒绝访问,返回“Host check error“。

之后就是正常的 Syncthing 使用,这个不难,看官方文档就可以了。

Syncthing 和 Nextcloud 配合工作

一开始我以为,把 Syncthing 的同步文件夹设置为我的 Nextcloud 的数据目录就可以完成同步,实际上 Nextcloud 的文件列表并不是实时的,需要运行 OCC 重新进行扫描,但是这样的扫描并不能保证数据完全无损,而且在使用时也不可能频繁 SSH 上去进行重扫,因此必须采取其他的方法。

关于这个问题,官方给出的答案是 External Storage,在 Nextcloud 中启用 External Storage 这个组件以后,在设置中挂载外部的文件夹,这个可以是本地,也可以是 SFTP/FTP/Amazon S3/WebDAV 等等,在这个情况下,我们选择本地,然后添加对应的文件夹就可以在 Nextcloud 文件列表中看到我们的文件了,无论是网页版还是手机都可以。

Syncthing 自动启动

在 Ubuntu 上,我们通过 systemd 服务来完成:

[Unit]
Description=syncthing
After=network-online.target

[Service]
ExecStart=/usr/bin/syncthing -no-browser -home="/home/www/.config/syncthing"
ExecStop=/bin/kill -9 $(/bin/cat /run/syncthing.pid)
Restart=always
PIDFile=/run/syncthing.pid
TimeoutStopSec=300
User=www

[Install]
WantedBy=multi-user.target

在 Windows 上,我们可以通过这样一个 .bat 完成启动:

start "Syncthing" syncthing.exe -no-console -no-browser

参考资料

https://docs.syncthing.net/
https://docs.nextcloud.com/server/13/admin_manual/
https://serverfault.com/questions/333321/executing-a-command-as-a-nologin-user
https://www.jianshu.com/p/4235cc85c32d

Ubuntu HWE Kernel 与 Linux CPU Frequency Scaling

其实 HWE Kernel 和 Frequency Scaling 是两个东西,只不过频率调节的工具是 Kernel 里面的一个组件,我因为没找到对应的 meta-package 而没有安装上正确的版本,然后发现是 HWE Kernel 和 GA Kernel 的不同版本造成的,所以想着干脆一起写篇东西解释一下这些东西的不同。

HWE Kernel

首先要说一说的是 HWE Kernel,按照官网的说法,是为了让 LTS 的 Linux 系统能够迅速支持最新的硬件,所以才命名为 HWE (HardWare Enable)。实际在使用过程中,可能也是我经验不足的原因,没碰上什么硬件太新 Kernel 不支持造成的 bug,所以这个名字怎么定义的其实意义不大。

在使用 Ubuntu 的过程中,应该都会遇到这样一种情况,Ubuntu 会帮我们自动更新内核,在 LTS 版本的 Roadmap 中,我们也可以看到不同的 point release 对应了不同的内核版本,比如 16.04.4 LTS 对应的就是 4.13 的内核。但有的时候,我们会发现,明明自己的系统已经是 16.04.4,为什么内核还是 4.4 版本呢?这是因为 HWE kernel 和 4.4 这样长期支持的 GA Kernel 其实是两个 meta-package,GA Kernel 对应的包是 linux-generic,下有 linux-image-generic 和 linux-headers-generic 这两个包,再往下才是具体的内核包。如果想要跟随 point release 更新系统的内核,那么就应该安装对应的 HWE 内核,HWE 内核是和 LTS 版本绑定的,比如 16.04 就需要加上 -hwe-16.04 后缀,那么对应的内核包就是 linux-generic-hwe-16.04,下面的包是 linux-headers-generic-hwe-16.04 和 linux-image-generic-hwe-16.04。使用这个包,就能安装最新的 4.13 内核(LTS 16.04.04)。

除了普通的 HWE 内核之外,还有一个更加激进的更新版本是 Rolling HWE Stacks,将上面的 -hwe-16.04 换成 -hwe-16.04-edge 就可以使用到这个 Stack。在这个 Stack 中可以提前使用 下一个 point release 中使用的 HWE 内核版本,就有点类似于 beta 测试的分支,这个可能会存在一定的稳定性问题,所以是否使用请自行斟酌。

CPU Frequency Scaling

接下来要说一说的是 CPU 频率调节的问题,在 Windows 上很多人应该都使用过的一个功能是电源方案,里面对 CPU 的最大频率、最小频率,散热方式等等可以做出一些自定义设置,Linux 上同样也提供了这样的功能。

在 Arch Wiki 中,对于这个问题有比较详细的介绍,在这里就简单地说一说:Linux 内核有自己的 CPU 调频实现,称为 cpufreq,这个在 3.4 的内核之后,必要的模块都会自行加载,用户也可以通过一些工具实现自己的调节。

CPU 频率的驱动程序随着 CPU 型号的不同会有很多的版本,具体可以查看 Arch Wiki 上面的说明,对于现在使用的 SandyBridge 以后架构的 CPU,通常使用 intel_pstate 来对频率进行调节。可以通过如下命令来查看 pstate 是否已经启用:

$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_driver

如果显示的都是 intel_pstate,那么你的 CPU 调节使用的就是 p-state 驱动。

CPU 频率的手动调节通常使用 cpupower 这个工具,可以通过如下的命令安装(需要和内核版本一直,这里使用 HWE Kernel 对应的版本):

$ sudo apt-get install linux-tools-common linux-tools-generic-hwe-16.04

之后运行 $ cpupower frequency-info就可以看到 CPU 的信息,大概是这样的输出:

$ cpupower frequency-info
analyzing CPU 0:
  driver: intel_pstate
  CPUs which run at the same hardware frequency: 0
  CPUs which need to have their frequency coordinated by software: 0
  maximum transition latency:  Cannot determine or is not supported.
  hardware limits: 1.60 GHz - 3.90 GHz
  available cpufreq governors: performance powersave
  current policy: frequency should be within 1.60 GHz and 3.90 GHz.
                  The governor "performance" may decide which speed to use
                  within this range.
  current CPU frequency: Unable to call hardware
  current CPU frequency: 3.70 GHz (asserted by call to kernel)
  boost state support:
    Supported: yes
    Active: yes
    3700 MHz max turbo 4 active cores
    3800 MHz max turbo 3 active cores
    3900 MHz max turbo 2 active cores
    3900 MHz max turbo 1 active cores

可以发现,信息比我们从 Windows 上面获取的要多得多,不仅可以看到当前的频率,还能看到最大睿频的信息。

Scaling Governors

Scaling Governor 相当于预设的 CPU 电源方案,在文档中有 6 种不同的调速器,但是在实际使用中,通常只有 performance 和 powersave 两种。performance 相当与强制 CPU 运行在最高频率,而 powersave 可以让 CPU 按需自动调节频率。当前在使用的调速器可以通过如下命令查看:

$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

通常来说默认配置是 powersave 模式,如果想调整为 performance,可以执行如下的命令:

$ sudo cpupower frequency-set -g performance

之后再进行查看,应该就是 performance 模式了,CPU 也会被固定在最大睿频上。

固定 Governor 不被修改

直接使用 cpupower 修改之后会存在一个问题,重启之后会被修改回 powersave,可以安装 cpufrequtils 将其固定:

$ sudo apt-get install cpufrequtils
$ sudo systemctl disable ondemand

一定要将 ondemand 这个服务关闭,这个服务会将 governor 设置为 ondemand 模式,但是通常 CPU 都不支持这个模式,然后就会 fallback 到 powersave。

之后在/etc/default/cpufrequtils中添加GOVERNOR="performance",重启即可。

Reference

https://wiki.archlinux.org/index.php/CPU_frequency_scaling_(简体中文)

https://wiki.ubuntu.com/Kernel/LTSEnablementStack

https://wiki.ubuntu.com/Kernel/RollingLTSEnablementStack

http://www.webupd8.org/2014/04/prevent-your-laptop-from-overheating.html

YACC 基本用法

YACC 文件格式

yacc 文件分为三部分:
… definitions …(%{}%)
%%
… rules …
%%
… subroutines …

定义部分

第一部分包括标志(token)定义和 C 代码(用“%{”和“%}”括起来)。
如在定义部分定义标志:
%token INTEGER
当运行 yacc 后,会产生头文件,里面包含该标志的预定义,如:
#ifndef YYSTYPE 
#define YYSTYPE int 
#endif 
#define INTEGER 258 
extern YYSTYPE yylval;
lex 使用该头文件中的标志定义。Yacc 调用 lex 的 yylex() 来获得标志(token),与标志对应的值由lex 放在变量 yylval 中。yylval 的类型由 YYSTYPE 决定,YYSTYPE缺省类型是int。如:
[0-9]+ { 
yylval = atoi(yytext); 
return INTEGER; 
}
标志0-255被保留作为字符值,一般产生的token标志从258开始。如:
[-+] return *yytext; /* return operator */
返回加号或减号。注意要把减号放在前面,避免被认作是范围符号。
对于操作符,可以定义 %left 和 %right:%left表示左相关(left-associative),%right 表示右相关(right-associative)。可以定义多组 %lef t或 %right,在后面定义的组有更高的优先级。如:
%left ‘+’ ‘-‘
%left ‘*’ ‘/’
上面定义的乘法和除法比加法和减法有更高的优先级。
改变 YYSTYPE 的类型。如这样定义 TTSTYPE:
%union
{ 
     int iValue; /* integer value */ 
     char sIndex; /* symbol table index */ 
     nodeType *nPtr; /* node pointer */ 
};

则生成的头文件中的内容是:

typedef union
{ 
     int iValue;      /* integer value */ 
     char sIndex;    /* symbol table index */ 
     nodeType *nPtr; /* node pointer */ 
} YYSTYPE; 
extern YYSTYPE yylval;

可以把标志(token)绑定到 YYSTYPE 的某个域。如:

%token <iValue> INTEGER
%type <nPtr> expr
把 expr 绑定到 nPtr,把INTEGER绑定到 iValue。yacc 处理时会做转换。如:
expr: INTEGER { $$ = con($1); }
转换结果为:
yylval.nPtr = con(yyvsp[0].iValue);
其中 yyvsp[0] 是值栈(value stack)当前的头部。
定义一元减号符有更高的优先级的方法:
%left GE LE EQ NE ‘>’ ‘<‘
%left ‘+’ ‘-‘
%left ‘*’
%nonassoc UMINUS
%nonassoc 的含义是没有结合性。它一般与 %prec 结合使用表示该操作有同样的优先级。如:
expr: ‘-‘ expr %prec UMINUS { $$ = node(UMINUS, 1, $2); }
表示该操作的优先级与 UMINUS 相同,在上面的定义中,UMINUS 的优先级高于其他操作符,所以该操作的优先级也高于其他操作符计算。

规则部分

规则部分很象 BNF 语法。
规则中目标或非终端符放在左边,后跟一个冒号(:),然后是产生式的右边,之后是对应的动作(用{}包含)。如:
%token INTEGER
%%
program: program expr '\n' { printf("%d\n", $2); } 

;
expr: INTEGER { $$ = $1; }  
     | expr '+' expr { $$ = $1 + $3; } 
     | expr '-' expr { $$ = $1 - $3; } 
;
%%
int yyerror(char *s) 
{ 
     fprintf(stderr, "%s\n", s); 
     return 0; 
}

其中,$1 表示右边的第一个标记的值,$2 表示右边的第二个标记的值,依次类推。$$ 表示规约后的值。

第三部分

该部分是函数部分。当 yacc 解析出错时,会调用函数 yyerror(),用户可自定义函数的实现。

main 函数是调用 yacc 解析入口函数 yyparse()。如:

int main(void) 
{ 
     yyparse(); 
     return 0; 
}

递归的处理

递归处理有左递归和右递归。
左递归形式:
list: item
| list ‘,’ item;
右递归形式:
list: item
| item ‘,’ list
使用右递归时,所有的项都压入堆栈里,才开始规约;而使用左递归的话,同一时刻不会有超过三个项在堆栈里。
If-Else的冲突
当有两个 IF 一个 ELSE 时,该 ELSE 和哪个 IF 匹配是一个问题。有两种匹配方法:与第一个匹配和与第二匹配。现代程序语言都让 ELSE 与最近的 IF 匹配,这也是 yacc 的缺省行为。
虽然 yacc 行为正确,但为避免警告,可以给 IF-ELSE 语句比 IF 语句更高的优先级:
%nonassoc IFX
%nonassoc ELSE
stmt: IF expr stmt %prec IFX
| IF expr stmt ELSE stmt
出错处理
当 yacc 解析出错时,缺省的行为是调用函数 yyerror(),然后从 yylex 返回一个值。一个更友好的方法是忽略一段错误输入流,继续开始扫描。这里要涉及到 YACC 中错误保留字 error 的应用。
Yacc源程序的风格
建议按照如下风格来写:
(1)终端符名全部用大写字母,非终端符全部用小写字母;
(2)把语法规则和语义动作放在不同的行;
(3)把左部相同的规则写在一起,左部只写一次,而后面所有规则都写在竖线“|”之后;
(4)把分号“;”放在规则最后,独占一行;
(5)用制表符来对齐规则和动作。
语法分析中的错误处理
当进行语法分析时发现输入串有语法错误,最好能在报告出错信息以后继续进行语法分析,以便发现更多的错误。
Yacc 处理错误的方法是:当发现语法错误时,yacc 丢掉那些导致错误的符号适当调整状态栈。然后从出错处的后一个符号处或跳过若干符号直到遇到用户指定的某个符号时开始继续分析。Yacc 内部有一个保留的终结符 error,把它写在某个产生式的右部,则Yacc就认为这个地方可能发生错误,当语法分析的确在这里发生错误时,Yacc 就用上面介绍的方法处理,如果没有用到 error的产生式,则 Yacc打印出 “Syntax error”,就终止语法分析。
下面看两个使用 error 的简单例子:
1.下面的产生式
stat: error
;
使 yacc 在分析 stat 推导出的句型时,遇到语法错误时跳过出错的部分,继续分析(也会打印语法错误信息)
2.下面的产生式
stat: error ‘;’
;
使 yacc 碰到语法错时,跳过输入串直到碰到下一个分号才继续开始语法分析。
嵌入式动作
对于语法分析程序中的每一个语法规则,都有相应的 C/C++ 语句来做一些额外的处理,这个额外的处理就是语法动作。不过语法动作和词法动作的不同之处在于,语法动作允许嵌入式的语法动作,而词法动作不行。
尽管 yacc 的语法分析技术只允许动作在规则的末端,但 yacc 可以自动模拟嵌入在规则内部的动作。如果在规则内部写入一个动作,yacc 就会创造一个右侧为空并且左边是自动生成的名字规则,使得嵌入的动作进高规则的动作里去,用自动成成的名字代替最初的规则内的动作。
例如: 下面的句子是等价的
thing : A {printf(“I am A”) ;} B
thing : A fakename B;
fakename : {printf(“I am A”);}
这种方式将A值作为 $1,  规则末端的动作可将嵌入式动作的值作为 $2 ,B 的值为 $3.
Example:
//L文件:
%{
#include "FIRST_TA.H"
#include <stdio.h>
#include <stdlib.h>
%}
%%
a    {return A_STATE;}
b    {return B_STATE;}
c     {return C_STATE;}
not   {return NOT;}
%%

//Y文件:
%{
#include <stdio.h>
#include <stdlib.h>
%}
%token    A_STATE B_STATE C_STATE NOT
%%

program :    
    A_STATE B_STATE {
        int c, d;
        c = 20;
        d = 25;
    }
      c_state_not  {
            int e,f;
            e = 30;
            f = 35;
        }
    |
    A_STATE B_STATE  {
            int a, b;
            a = 10;
            b = 15;
    }
    c_state_not : C_STATE NOT{}
%%

输入文件的字符:a, b, c, f, c, not

关于 qBittorrent 部分问题的记录

首先是这个反复弹出 Tracker Authentication 窗口的问题,这个是因为 Tracker 对未授权的种子返回了 HTTP/401 错误,导致 qb 弹出窗口要求验证。这是一个正常行为,如果不需要它:

  • 在 qBittorrent/src/base/bittorrent/torrenthandle.cpp 文件的 void TorrentHandle::handleTrackerErrorAlert(libtorrent::tracker_error_alert *p) 函数中注释掉关于 401 错误的两行即可。

然后就是在 qb 中有大量种子的情况下,同时开始会导致 Tracker 始终处于 “Not Working” 状态,如果一个一个启动,那么就是好的,这个应该是qb本身并发设计不良导致的问题。