0%

起因

同学说 Zoom 卡,影响了他在线考试。我们收集了一些资料后发现 Zoom 有中国服务器,但是只有商业用户可以连接,而免费账户只能连接到美国的服务器。我怀疑是中国到 Zoom 的美国服务器网络线路不好。

我们尝试了下发现挂代理也没用——尽管 Zoom 已经检测到了代理(在统计信息页面)。我同学说他那边丢包,我这边感觉还好,但有时候也有丢包。我担心是 UDP 请求不能被正常代理

补充:几种代理方式的能力范围

HTTP 代理

支持 IPv4 和 IPv6,仅能代理 TCP。

https://superuser.com/a/302955/ 来看,虽然其主要是代理 HTTP(当然也能代理 HTTPS),但许多 HTTP 代理服务器能够处理 CONNECT 请求(因此实际上支持了裸 TCP 连接),所以 HTTP 代理也能用来代理其他 TCP 协议。

SOCKS4 代理

支持 IPv4 的 TCP 请求。

我的主要代码是这样:

def main():
    with tempfile.TemporaryDirectory() as d:
        write_tmp_files(d)

即便是程序在终端被 ^C 终止,临时文件夹也会被正常清理,但是我发现 SIGHUP 到来时,临时文件夹就不会被正常清理了。可以注册一个信号处理器函数:

import signal
import sys

signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit(0)) # 其实应该改成信号值 + 128

这样在 SIGHUP 到来时,临时目录也会被正常清理。

https://docs.docker.com/engine/security/seccomp/

seccomp 选项可以控制容器内可以执行的系统调用。可以用 --security-opt seccomp=/path/to/seccomp/profile.json,也可以用 --security-opt seccomp=unconfined 表示不受限。

This feature is available only if Docker has been built with seccomp and the kernel is configured with CONFIG_SECCOMP enabled.

之所以用这个选项,是前段时间有个要跑的服务启动失败了,和其他同类服务比较发现没有加 seccomp 选项。

对数据集的文件名正确排序

有些训练或评估程序要求数据集输入文件的顺序严格有序 1,但是文件名长度又不同,不能简单按照字典序来排序。比如,数据集的标签文件名可能是 0.txt、1.txt……10.txt 等,能想到的一个方法是在前面填充字符 '0'

lst = os.listdir(directory)
lst = sorted(lst, key=lambda s : s.zfill(50))

如果先去掉后缀名,然后再把前面的字符串转数字,则可能会遇到很多复杂的情况(比如多重后缀名),比不上在前面填充字符简单。

zfill 填充好之后,文件名都是这样的:

00000...001.txt
00000...002.txt
...
00000...100.txt

cv2 的参数输入格式

cv2 全部改成了用 numpy.ndarray 作为图像处理格式。只是操作图像的时候:

  1. 数据类型必须是 uint8。
  2. 形状必须是 (H, W, C) 或者 (H, W),后者为灰度图。
  3. 必须是连续的,必要时得用 np.ascontiguousarray() 转换一下(不然报错会很晦涩)。

如果使用训练模型用的张量转 numpy,一定要记得把批量维度去掉,并且转 channels-last 格式。否则 cv2 不能正常识别图像,并可能报错(报错信息晦涩难懂)。

此外,pillow 库的 Image 默认格式为 RGB,而 cv2 中图像的默认格式为 BGR,需要按需转换。

cv.imwrite()

cv2.imwrite() 是将 numpy 数组表示的图像写入到磁盘。

原文

https://developer.nvidia.com/blog/using-cuda-warp-level-primitives/

笔记

Warp 内规约

#define FULL_MASK 0xffffffff
for (int offset = 16; offset > 0; offset /= 2)
    val += __shfl_down_sync(FULL_MASK, val, offset);

先在 warp 内用原语规约,比在 block 级别用共享内存规约快很多。(虽然也有 __reduce_add_sync() 函数,但是截至 2024 年 9 月 5 日只支持 unsigned 和 int 类型,给浮点数做规约就要用 __shfl_xx_sync() 系列。)

CUDA 9 的相关 API

直接从原博客摘录:

原文链接

https://developer.nvidia.com/blog/cuda-pro-tip-optimized-filtering-warp-aggregated-atomics/

场景

src 中大于 0 的数字移动到 dst 中去,并返回新数组的元素数量。和 C++ 的 std::copy_if 相似。

int filter(int *dst, const int *src, int n) {
  int nres = 0;
  for (int i = 0; i < n; i++)
    if (src[i] > 0)
      dst[nres++] = src[i];
  // return the number of elements copied
  return nres;
}

如果用全局内存实现:

__global__ 
void filter_k(int *dst, int *nres, const int *src, int n) {
  int i = threadIdx.x + blockIdx.x * blockDim.x;
  if(i < n && src[i] > 0)
    dst[atomicAdd(nres, 1)] = src[i];
}

本机没有 NVIDIA GPU,只是无聊想要试试能不能在没有 GPU 的机器(宿主机没 GPU)上做编译工作

按照 官网链接,选择 Ubuntu 即可。cuda-repo-ubuntu2404-12-6-local_12.6.1-560.35.03-1_amd64.deb 这个文件占了 3.2G,安装之后就更大了。

安装完成之后,可以在 /usr/local/cuda-12.6/bin/ 中找到 nvcc。加到 PATH 之后,编译都能正常进行,但是因为没有 GPU,运行时 CUDA 相关的 API 都会报错,仅此而已。

基本认识

伪终端解决这样的问题:远程登录等场合,用户并不能和真正的终端进行交互,而且信息也不能简单通过 socket 转发,因为很多(面向终端的)应用程序是假设了有控制终端的。应用了伪终端的程序包括:script(1)(能录制本次交互程序的全部用户输入和用户能看到的输出)、screen(1)、expect(1)(在 一个可以用来测试某交互程序的是否如期运行的工具,在 Debian 上需要额外安装)、xterm 等终端模拟器

伪终端很像一个双向管道。主设备写入、从设备可以读;从设备写入、主设备可以读。在从设备侧,伪终端表现得就和真实终端一样:所有在终端上能使用的系统调用在伪终端上都不会报错,对伪终端无意义的设置也会被忽略。因此,驱动程序(接收用户输入)面向主设备,应用程序面向从设备(它们对自己使用的是真实终端还是伪终端可能并不知情)。

System V (UNIX 98) 伪终端

  • posix_openpt() 函数可以打开一个未使用的伪终端主设备,返回其 fd。
  • grantpt() 可用于修改对应的从设备的属组和权限。
  • unlockpt() 用于解锁从设备,这样从设备就能被打开了(这是为了应对竟态条件)。
  • ptsname() 函数返回主设备对应的从设备名称。

posix_openpt()O_NOCTTY 标志可以使得伪终端主设备不成为当前进程的控制终端,在 Linux 上是默认启用的;O_RDWR 标志以读写方式打开,一般开发者都会指定此标志。最初 System V 终端实现中,获取主设备是通过打开伪终端主克隆设备 /dev/ptmx 实现的。也就是说,posix_openpt() 完全可以被实现为:

int
posix_openpt(int flags)
{
    return open("/dev/ptmx", flags);
}

这是我写的某个测试的脚本:

  1. B 需要等待 A 程序先运行起来之后才能启动。
  2. A 退出之后,应该中止 B。
  3. 代码能保证 B 不会在 A 之前中止。
#!/bin/bash

./build/test/A -n 5000 &
PROC_A=$!
sleep 3
python test/B.py &
PROC_B=$!
tail --pid=$PROC_A -f /dev/null
kill $PROC_B

tail --pid=$PROC_A -f /dev/null 这一句是等待特定进程结束的关键。参考 https://stackoverflow.com/questions/1058047/wait-for-a-process-to-finish