Category Archives: Debug

在Hifive unmatched上安装FreeBSD

最近手痒想试试FreeBSD,正好FreeBSD ports 也在找一台builder,吴博给我凑了2台Unmatched 跑Linux的Go builder,所以我这台就空出来了~

其实按着官方的教程就好,官方教程:https://wiki.freebsd.org/riscv/HiFiveUnmatched

不过要注意2点!!(花了我两个晚上),一切的错误都从我没仔细看教程开始……第一个错误是直接把FreeBSD的镜像直接烧进了SD卡里!然后以为这就行了~结果发现,其实Unmatched的固件决定了必须从SD上特定的分区才能启动!所以直接烧进SD卡里,应该是根据教程写进一个U盘里。

诡异的是,重新给SD卡烧录了Ubuntu的镜像,系统nvme就因为找不到root直接进(initramfs)了。

我脑子抽了就直接用SD卡里的Ubuntu shell 直接 dd if=/dev/zero of=/dev/nvme0n1 …… 想通过干掉分区表(GPT)来阻止从nvme启动。结果噩梦就开始了,SD卡里的Ubuntu怎么都找不到nvme和U盘了。折腾了一晚没啥收获,第二天不停的重启和对比才发现。UBoot启动的过程中需要启动pci!要不然你怎么执行命令启动USB都是不行的,usb start 就会报错 no working controllers found

所以正确的做法是,在U-boot自动启动过程中先启动pci 子系统

pci enum
setenv boot_targets usb0
boot

最后就是标准的FreeBSD安装流程了~ yes~

程序中的时间问题

leap second

最近Russ Cox提了一条proposal《Monotonic Elapsed Time Measurements in Go》

这个proposal主要解决了一个问题,计算时间差。
我一开始觉得,这不是很简单么?例如:

t1 := time.Now()# ... 10 ms of work 
t2 := time.Now() 
const f = "15:04:05.000" 
fmt.Println(t1.Format(f), t2.Sub(t1), t2.Format(f))

简单的相减,就可以得到时间差。但这里隐含了一个谬误,就是:

默认:程序后执行的Now,肯定比之前执行的Now晚。

时间,在人的认知里肯定是单向向前,但在计算机系统里,却不是。因为有正、负闰秒的存在,常常有bug出现,例如:Cloudflare RRDNS 故障

这起事故中,CF的RRDNS使用两个时间的差值进行权重计算,平时是没有问题,但当闰秒的出现时,程序差值就出现了负数,最终酿成了事故。所以在对时间差有严重依赖的程序(纳入计算权重等),需要使用的是monotonic time(单调递增时间),而不是wall time(系统时间),这也就促成了Russ Cox的proposal。

不但如此,程序员还有对于时区、时差、时间精度、起始的谬误。因此,就有人总结出了《程序员认知时间的谬误(Falsehoods programmers believe about time)》 ,我摘抄了部分国内程序员常犯的错误,括号中是我个人对于这些谬误的理解:

  1. 一天总有24小时
  2. 一个月有30或者31天(还有二月份)
  3. 一年有365天 (闰秒导致多一秒,1582年整整消失了10天
  4. 二月份总是28天(有29天)
  5. 24小时是一天、周、月的周期值(对时间取模算天数、我也犯过)
  6. 每年相同月份里,周的起始是相同的
  7. 机器的时区永远是GMT,不,开玩笑的,是机器的时区永远不变(时区的设置可能会被调整)
  8. 系统时钟永远设置的是本地对应的时区的时间
  9. 目标时区和GMT永远有相同的间隔时间(时区会变化,夏令时)
  10. 客户端的时间和服务器时间永远相同
  11. 客户端时间和服务器时间的差值没什么大不了的
  12. 就算CS有差值,总是相同的间隔(客户端可能会动态调整时间)
  13. 服务器和客户端的时间永远在同一个时区
  14. 系统时间不会在5000年前、或者5000年后
  15. 时间没有起点和尽头(千年虫、Unix epoch)
  16. 系统中的一分钟和其他机器上的一分钟应该是一样的(各个机器上CPU频率等问题导致时钟偏移,所以请使用ntp)
  17. 最小的时间单位是秒、呃、毫秒……(最小单位是CPU确定的)
  18. 大家都能明白时间戳格式(1339972628 或者是 133997262837)
  19. 时间戳格式永远是同一个格式(64位和32位就有区别)
  20. 时间戳精度永远相同(float精度问题)
  21. 时间戳的精度保证了可以做uid
  22. 全世界都能明白11/07/05是什么时间格式(年月日显示格式不明确)

我的经历中,见得比较多的是对于时区了解的匮乏,很多程序员并不知道夏令时,甚至有产品或者老板的需求就只是给国人服务,当要全球化时就抓瞎了。当然,最多的还是对闰秒的无视,或者有人根本不知道闰秒的存在。不过,这些bug都因为系统对时间依赖程度不高,或因为系统跑的时间不够长,(没长到碰到闰秒就下线了),所以并没有导致算错帐或者生产事故。不过,这些理由都不能为这种bug开脱,所以程序员要学习东西还是很多的。

p.s. 你在生产系统里碰到过什么关于时间的bug?欢迎讨论~