esp32在Arduino 1.8下的I2C引脚

终于知道为什么esp的IO21和IO22引脚是SDA和SCL的默认接口。
恐惧:恐惧是给C++的,我这几天正好在网上看到别人说,C++语法可以特别特别恶心,常量特别特别难定位。我就在想有多难,有多恶心,CTRL+f很快就定位到了。然后这几天头头在捣鼓传感器,我就在旁边看着,学习学习。记下了当时他接的引脚号,回去自己捣鼓捣鼓,一般来说,接传感器都是要在程序里指定引脚的,我看了看样例代码里也没有指定就很纳闷(我也在头文件里面找,也没找到)。就问头头,为什么=这个不指定引脚啊?头头很随意的说“因为这个是使用I2C的接口,只需要指定传感器的编号(相当于人的手机号,每类传感器都有一个,也可以人为设定),esp32会自动扫描在总线上的设备,不用管接哪个引脚。”那我听了这话,就很感慨,原来现在传感器也这么智能了,就试了试其他的引脚,不行,我大概尝试了几十种组合方式,除了头头的那一种其他的都不行。这个时候也不好意思去问头头 ,感觉很简单的一个东西。于是就上网看看I2C协议,再看看一些实例,哦,原来随便接是说在同一个I2C接口上可以随便接很多个传感器,在这个I2C接口上会自动的扫描不同的传感器设备。好,那我们来看看esp32上的I2C接口是哪个引脚。如果不出所料应该是头头用的IO21,22

继续阅读esp32在Arduino 1.8下的I2C引脚

根据温度、气压计算海拔高度

有趣的是,这个简单的内容居然在国内的网站上很难搜索。不过无妨,毕竟是学过多年英语的人,链接在此。闲话不说,请看公式

1. hypsometric 公式

$ \Large h = \frac{[(\frac{P_0}{P})^{\frac{1}{5.257}}-1] \times (T + 273.15)}{0.0065} \tag{1}$

(1)

其中,$P_0$为标准大气压强,取值 $101.325 {\rm kPa}$; $P$为实际测量的大气压强,单位 ${\rm kPa}$; $T$为实际测量温度,单位 ℃。

上式中( T + 273.15 )是将摄氏度转化为华氏度。该公式同时考虑为温度和压强计算海拔高度,计算结果的单位是米。

2. barometric 公式

$\Large h = 44330 \times \left [ 1 - (\frac{P}{P_0})^{\frac{1}{5.255}} \right ] \tag{2}$

(2)

其实该公式只是只是(1)式在一定条件下取值,不考虑温度的影响,计算结果的单位是米。

继续阅读根据温度、气压计算海拔高度

MicroPython入坑记(四)关于MicroPython的代码保护

脚本开发东西,可能面临的第一个问题就是:拷给别人,代码怎么写的他不就都知道了?不行,我要保住我的小秘密!

先说下结果:没有攻不破的堡垒,即使你写成C语言,只要能拿到二进制结果,都可以反汇编逆向出你是怎么实现的,关键是值不值得

另外,这跟逆向者对系统的了解程度有关,比如对方连代码都不会上传,那你即使把源文件放进去也他也无可奈何。

好了,言归正传,我们知道普通python有个编译成字节码的功能,也就是源代码会在解释时先编译成一个类似java中间代码的结果,这是不可读的(但是这也不排除反编译的可能,毕竟JAVA的class文件是有反编译软件的)。

micropython也有这个功能,不过这个文件的扩展名是mpy,也不能在运行时自动生成,需要一款软件:mpy-cross.exe,这是micropython官方提供的,可以用python pip直接安装,安装完成后,可以运行mpy-cross.exe pythonfile,py,就可以生成一个pythonfile.mpy的字节码文件,这文件使用跟py文件是等效的。把所有文件生成mpy,可以在一定程度上保护你的代码。

更进一步的方式:把mpy文件藏到固件中去,这不光能保护代码,还能降低程序的内存占用,官方的描述如下:

Cross-installing packages with freezing

For the low-memory MicroPython ports, the process described in the previous section does not provide the most efficient resource usage,because the packages are installed in the source form, so need to be compiled to the bytecome on each import. This compilation requires RAM, and the resulting bytecode is also stored in RAM, reducing its amount available for storing application data. Moreover, the process above requires presence of the filesystem on a device, and the most resource-constrained devices may not even have it.

The bytecode freezing is a process which resolves all the issues mentioned above:

  • The source code is pre-compiled into bytecode and store as such.
  • The bytecode is stored in ROM, not RAM.
  • Filesystem is not required for frozen packages.

Using frozen bytecode requires building the executable (firmware) for a given MicroPython port from the C source code. Consequently, the process is:

  1. Follow the instructions for a particular port on setting up a toolchain and building the port. For example, for ESP8266 port, study instructions in ports/esp8266/README.md and follow them. Make sure you can build the port and deploy the resulting executable/firmware successfully before proceeding to the next steps.
  2. Build MicroPython Unix port and make sure it is in your PATH and you can execute micropython.
  3. Change to port’s directory (e.g. ports/esp8266/ for ESP8266).
  4. Run make clean-frozen. This step cleans up any previous modules which were installed for freezing (consequently, you need to skip this step to add additional modules, instead of starting from scratch).
  5. Run micropython -m upip install -p modules <packages>... to install packages you want to freeze.
  6. Run make clean.
  7. Run make.

After this, you should have the executable/firmware with modules as the bytecode inside, which you can deploy the usual way.

大体的意思是这样的:运行py文件不能有效的使用内存资源,因为代码执行时需要被编译成bytecode代码,该编译需要RAM,生成的字节码也存在RAM中,这就降低了可用内存。并且存储py文件需要文件系统,而一些嵌入设备本身不存在文件系统。

嗯,神一样的保护功能,不但降低了内存占用,还把字节码藏到了固件中,代价就是需要自己编译micropython固件。

参考链接


MicroPython入坑记(四)关于MicroPython的代码保护

Whistle 是基于 Node 实现的跨平台抓包调试工具

Whistle 是基于 Node 实现的跨平台抓包调试工具,其主要特点:

  1. 完全跨平台:支持 Mac、Windows 等桌面系统,且支持服务端等命令行系统
  2. 功能强大(理论上可以对请求做任意修改)
    • 支持作为 HTTP、HTTPS、SOCKS 代理及反向代理
    • 支持抓包及修改 HTTP、HTTPS、HTTP2、WebSocket、TCP 请求
    • 支持重放及构造 HTTP、HTTPS、HTTP2、WebSocket、TCP 请求
    • 支持设置上游代理、PAC 脚本、Hosts、延迟(限速)请求响应等
    • 支持查看远程页面的 console 日志及 DOM 节点
    • 支持用 Node 开发插件扩展功能,也可以作为独立 npm 包引用
  3. 操作简单
    • 直接通过浏览器查看抓包、修改请求
    • 所有修改操作都可以通过配置方式实现(类似系统 Hosts),并支持分组管理
    • 项目可以自带代理规则配置并一键设置到本地 Whistle 代理,也可以通过定制插件简化操作

继续阅读Whistle 是基于 Node 实现的跨平台抓包调试工具

nvidia-smi GPU性能状态(Performance State)含义

我正在使用Nvidia GTX Titan X进行深度学习实验。
我正在使用nvidia-smi来监视GPU的运行状态,但是提供的工具的性能(性能)状态没有意义。

我已经查看了nvidia-smi手册,它表示以下内容:

Performance State
The current performance state for the GPU. States range from P0 (maximum performance) to P12 (minimum performance).

如果不在GPU上运行任何进程(空闲状态),则GPU性能状态为p0。
但是,当运行一些计算繁重的过程时,状态变为p2。

我的问题是,为什么我的GPU闲置时处于P0状态,但是在执行繁重的计算任务时切换到P2? 不应该相反吗?

另外,有没有办法使我的GPU始终在P0状态下运行(最高性能)?


令人困惑。

但是,nvidia-smi手册是正确的。

当一个或一组GPU处于空闲状态时,在计算机上运行nvidia-smi的过程通常会使其中一个GPU退出空闲状态。这是由于该工具正在收集的信息-需要唤醒其中一个GPU。

此唤醒过程最初会将GPU置于P0状态(最高性能状态),但如果GPU空闲或不是特别忙碌,GPU驱动程序将监控该GPU,并最终开始降低性能状态以节省功耗。

另一方面,当GPU在工作负载下处于活动状态时,GPU驱动程序将根据其自身的启发式方法不断调整性能状态以提供最佳性能,同时使性能状态与实际工作负载相匹配。如果没有达到热或功率限制,则对于最活跃和最重的连续工作负载,性能状态应达到最高水平(P0)。

周期性很重但不连续的工作负载可能会导致GPU功耗状态在P0-P2级别附近波动。由于热(温度)或电源问题而"受限制"的GPU也可能会看到P状态降低。这种限制是显而易见的,并在nvidia-smi中单独报告,但是可能并非所有GPU类型都启用这种报告。

如果要在GPU上查看P0状态,我可以提供的最佳建议是运行短暂,繁重且连续的工作负载(例如,执行大型sgemm操作的工作),然后在该工作负载期间监视GPU。在这种情况下应该可以看到P0状态。

如果您使用的是正在使用cuDNN库的机器学习应用程序(例如Caffe),并且正在训练大型网络,则应该可以不时看到P0,因为cuDNN会执行类似于sgemm的操作通常情况下。

但是对于零星的工作负载,最常见的状态很有可能是P2。

要始终"强制" P0电源状态,可以尝试通过nvidia-smi工具尝试持久性模式和应用程序时钟。使用nvidia-smi --help或nvidia-smi的手册页了解选项。

尽管我认为这通常不适用于Tesla GPU,但除非特别设置更高的应用时钟,否则某些NVIDIA GPU可能会在计算负载下将自身限制为P2功耗状态。使用nvidia-smi -a命令查看可用于GPU的当前应用程序时钟,默认应用程序时钟和最大时钟。 (某些GPU(包括较旧的GPU)可能会在其中某些字段中显示N / A。这通常表明应用程序时钟无法通过nvidia-smi进行修改。)如果在计算负载期间卡似乎以P2状态运行,则可能通过将应用程序时钟增加到最大可用时钟(即最大时钟),可以将其增加到P0状态。使用nvidia-smi --help了解如何格式化命令以更改GPU上的应用程序时钟。修改应用程序时钟或启用可修改的应用程序时钟可能需要root / admin特权。设置GPU持久模式也可能是理想的或必要的。这将防止驱动程序在GPU活动期间"卸载",这可能导致驱动程序重新加载时重置应用程序时钟。

对于这种情况下受影响的卡,此默认行为是在计算负载下限制为P2,这是由GPU驱动程序设计的。

参考链接


[华硕主板] 支持ECC内存的AMD Ryzen™处理器列表

下表列出了支持带ECC功能内存模组的Ryzen™处理器的列表;它们的官方名称;以及是否支持B550X570系列。

请注意,当涉及到APUsRyzen 3000/4000 G系列),只有PRO处理器(例如Ryzen 3 PRO 3200G)支持ECC内存。

官方名称

支持B550系列

支持X570系列

ECC功能

UDIMM ECC

REG ECC

AMD Ryzen™ 5000 Series Processors

V

V

支持

V

 

AMD Ryzen™ 4000 G-Series Processors

V

V

只有PRO支持

V

 

AMD Ryzen™ 3000 Series Processors

V

V

支持

V

 

AMD Ryzen™ 2000 Series Processors

 

V

支持

V

 

AMD Ryzen™ 3000 G-Series Processors

 

V

只有PRO支持

V

 

注意,Ryzen™处理器只支持二手UDIMM ECC,不支持更便宜的二手REG ECC

这个问题简单解释一下,新的REG ECC从性能到价格都是远远高于UDIMM ECC的,但是REG ECC不能用在家用主板上,导致大量淘汰的二手内存需求量不高,因而价格偏便宜。

继续阅读[华硕主板] 支持ECC内存的AMD Ryzen™处理器列表

运维中tcp_tw_recycle net.ipv4.tcp_timestamps引发的坑

NAT环境下,遇到因为tcp_tw_recycle=1和net.ipv4.tcp_timestamps=1引起 Nginx upstream timed out 后,一直没在遇见,今天在朋友的阿里云环境下又重新再一次出现;因此在这炒一次冷饭,让运维新手或者刚上云的朋友大概了解一下,避免再一次采坑。

故障情况:

阿里云账号A的A机房,内网里面部署两台Nginx,通过网络出口(NAT),代理用户访问到阿里云账号B的B机房服务。A机房的Nginx出现:upstream timed out 。

故障的诱因是:net.ipv4.tcp_timestamps=1

抓包图:

注意,这个选项生效的前提是,报文的发出方必须在TCP头部的可选项中增加时间戳字段,否则这个设置是不生效的。

直接上当年的笔记:

先看看TCP IP 对tw的一些解析:
RFC 1323里有这样的定义:

An additional mechanism could be added to the TCP, a per-host
cache of the last timestamp received from any connection.
This value could then be used in the PAWS mechanism to reject
old duplicate segments from earlier incarnations of the
connection, if the timestamp clock can be guaranteed to have
ticked at least once since the old connection was open.  This
would require that the TIME-WAIT delay plus the RTT together
must be at least one tick of the sender's timestamp clock.
Such an extension is not part of the proposal of this RFC.

大概的中文意思就是:TCP协议中有一种机制,缓存了每个主机(即ip)过来的连接最新的timestamp值。这个缓存的值可以用于PAWS(Protect Against Wrapped Sequence numbers,是一个简单的防止重复报文的机制)中,来丢弃当前连接中可能的旧的重复报文。而Linux实现这个机制的方法就是同时启用net.ipv4.tcp_timestamps和net.ipv4.tcp_tw_recycle 这两个选项。
这种机制在 客户端-服务器 一对一的时候,没有任何问题,但是当服务器在负载均衡器后面时,由于负载均衡器不会修改包内部的timestamp值,而互联网上的机器又不可能保持时间的一致性,再加上负载均衡是会重复多次使用同一个tcp端口向内部服务器发起连接的,就会导致什么情况呢:

负载均衡通过某个端口向内部的某台服务器发起连接,源地址为负载均衡的内部地址——同一假如恰巧先后两次连接源端口相同,这台服务器先后收到两个包,第一个包的timestamp被服务器保存着,第二个包又来了,一对比,发现第二个包的timestamp比第一个还老——客户端时间不一致。服务器基于PAWS,判断第二个包是重复报文,丢弃之。

反映出来的情况就是在服务器上抓包,发现有SYN包,但服务器就是不回ACK包,因为SYN包已经被丢弃了。为了验证这一结果,可以执行netstat -s | grep timestamp 命令,看输出里面passive connections rejected by timestamp 一项的数字变化。

tcp_ipv4.c中,在接收SYN之前,如果符合如下两个条件,需要检查peer是不是proven,即per-host PAWS检查:

  • 收到的报文有TCP option timestamp时间戳
  • 本机开启了内核参数net.ipv4.tcp_tw_recycle
		/* VJ's idea. We save last timestamp seen
		 * from the destination in peer table, when entering
		 * state TIME-WAIT, and check against it before
		 * accepting new connection request.
		 *
		 * If "isn" is not zero, this request hit alive
		 * timewait bucket, so that all the necessary checks
		 * are made in the function processing timewait state.
		 */
		if (tmp_opt.saw_tstamp &&
		    tcp_death_row.sysctl_tw_recycle &&
		    (dst = inet_csk_route_req(sk, &fl4, req)) != NULL &&
		    fl4.daddr == saddr) {
			if (!tcp_peer_is_proven(req, dst, true)) {
				NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
				goto drop_and_release;
			}
		}

解决办法:

tcp_tw_recycle=0 或(和)net.ipv4.tcp_timestamps=0同时从4.10内核开始,官方修改了时间戳的生成机制,所以导致 tcp_tw_recycle 和新时间戳机制工作在一起不那么友好,同时 tcp_tw_recycle 帮助也不那么的大。

此处的时间戳并不是我们通常意义上面的绝对时间,而是一个相对时间。很多情况下,我们是没法保证时间戳单调递增的,比如业务服务器之前部署了NAT,LVS等情况。相信很多小伙伴上班的公司大概率实用实用各种公有云,而各种公有云的 LVS 网关都是 FullNAT 。所以可能导致在高并发的情况下,莫名其妙的 TCP 建联不是那么顺畅或者丢连接。

而这也是很多优化文章中并没有提及的一点,大部分文章都是简单的推荐将net.ipv4.tcp_tw_recycle设置为1,却忽略了该选项的局限性,最终造成严重的后果(比如我们之前就遇到过部署在nat后端的业务网站有的用户访问没有问题,但有的用户就是打不开网页)。

参考链接