找回密码
 立即注册
首页 业界区 安全 交易系统开发——张智炫

交易系统开发——张智炫

孔季雅 6 小时前
实际项目请根据侧边目录手动跳转至实际项目部分,本项目实践学习及来源于
Building Low Latency Applications with C++.pdf
部分基础知识来源:
https://weedge.github.io/perf-book-cn/zh/
https://arxiv.org/abs/2309.04259
Testing and Tuning Market Trading Systems _ Algorithms in -- Timothy Masters -- 1st ed_ 2018, Berkeley, CA, 2018 -- Apress _ Imprint_ Apress -- 9781484241721 -- 60d1a98d33720c15e03ee33c4ae10155 -- Anna’s Archive.pdf
optimizing_cpp.pdf
项目代码地址:https://github.com/zzxscodes/zquant-system
低延迟系统开发基础

1. CPU亲和性及NUMA架构

isolcpus:内核启动参数CPU隔离
  1.   编辑 /etc/default/grub 。
  2.   修改 GRUB_CMDLINE_LINUX_DEFAULT  这一行, 在引号内添加 isolcpus=cpu号列表 (例如: isolcpus=2,3  isolcpus=1,4-7)。
  3.   执行 sudo update-grub (Debian/Ubuntu) ( sudo grub2-mkconfig -o /boot/grub2/grub.cfg(RHEL/CentOS/Fedora)) 并 sudo reboot。
复制代码
taskset:命令行工具CPU绑定
  1.   启动进程: taskset -c 1 ./my_app  (在CPU 1上运行)
  2.   修改运行中进程:taskset -pc 3 <PID>  (将PID进程移至CPU 3)
  3.   查询进程:taskset -pc <PID>
  4.   绑定进程下的线程: ps -T -p <PID> taskset -p -c <CPU列表> <TID>
复制代码
pthread_setaffinity_np(sched_setaffinity):线程(进程)CPU绑定
  1. #pragma once
  2. #include <iostream>
  3. #include
  4. #include <thread>
  5. #include <unistd.h>
  6. #include <sys/syscall.h>
  7. namespace Common {
  8.     /// Set affinity for current thread to be pinned to the provided core_id.
  9.     inline auto setThreadCore(int core_id) noexcept {
  10.         cpu_set_t cpuset;
  11.         CPU_ZERO(&cpuset);
  12.         CPU_SET(core_id, &cpuset);
  13.         return (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) == 0);
  14.     }
  15.     /// Creates a thread instance, sets affinity on it, assigns it a name and
  16.     /// passes the function to be run on that thread as well as the arguments to the function.
  17.     template<typename T, typename... A>
  18.     inline auto createAndStartThread(int core_id, const std::string &name, T &&func, A &&... args) noexcept {
  19.         auto t = new std::thread([&]() {
  20.             if (core_id >= 0 && !setThreadCore(core_id)) {
  21.                 std::cerr << "Failed to set core affinity for " << name << " " << pthread_self() << " to " << core_id << std::endl;
  22.                 exit(EXIT_FAILURE);
  23.             }
  24.             std::cerr << "Set core affinity for " << name << " " << pthread_self() << " to " << core_id << std::endl;
  25.             std::forward<T>(func)((std::forward(args))...);
  26.         });
  27.         using namespace std::literals::chrono_literals;
  28.         std::this_thread::sleep_for(1s);
  29.         return t;
  30.     }
  31. }
  32. /*
  33. * sched_setaffinity 和 pthread_setaffinity_np 的区别:
  34. *
  35. * 1. 作用对象:
  36. * - pthread_setaffinity_np: 作用线程,通过 pthread_t 句柄来指定要绑定的线程。
  37. * - sched_setaffinity: 作用进程。它通过进程ID (PID) 来指定要绑定的进程。
  38. * 一个进程被绑定,所有子线程也会被限制在这个CPU中。
  39. * 2. 可移植性:
  40. * - pthread_setaffinity_np: GNU C 库(glibc)扩展。
  41. * - sched_setaffinity: 标准 Linux 系统调用。
  42. */
复制代码
11.内存对齐与典型内存布局优化
  1. #!/usr/bin/env bash
  2. #
  3. # simple_cpuset_example.sh
  4. #
  5. # 演示如何使用 cpuset 将一个任务绑定到专属的 CPU 核心。
  6. # --- 配置 ---
  7. # 为后台任务分配的常规核心
  8. SYSTEM_CORE="0"
  9. # 为专属任务保留的核心
  10. EXCLUSIVE_CORE="1"
  11. set -e
  12. # 确保脚本以 root 权限运行
  13. if [[ $(id -u) -ne 0 ]]; then
  14.     echo "此脚本必须以 root 身份运行。"
  15.     exit 1
  16. fi
  17. # 1. 创建 cgroup 目录
  18. echo "--> 正在创建 cpuset 核心池..."
  19. mkdir -p /sys/fs/cgroup/cpuset/exclusive_tasks
  20. # 2. 配置独占核心池
  21. # 将核心 1 分配给这个池
  22. echo "${EXCLUSIVE_CORE}" > /sys/fs/cgroup/cpuset/exclusive_tasks/cpuset.cpus
  23. # 将其标记为 CPU 独占
  24. echo "1" > /sys/fs/cgroup/cpuset/exclusive_tasks/cpuset.cpu_exclusive
  25. # 将内存节点 0 分配给这个池(通常一个核心只有一个内存节点)
  26. echo "0" > /sys/fs/cgroup/cpuset/exclusive_tasks/cpuset.mems
  27. # 3. 运行一个任务并将其绑定到独占核心池
  28. echo "--> 正在启动一个无限循环并绑定到核心 ${EXCLUSIVE_CORE}..."
  29. # 启动一个后台任务
  30. while true; do :; done &
  31. TASK_PID=$!
  32. echo "任务 PID: ${TASK_PID}"
  33. # 将任务的 PID 写入独占池的 tasks 文件中
  34. echo "${TASK_PID}" > /sys/fs/cgroup/cpuset/exclusive_tasks/tasks
  35. echo "任务已成功绑定。可以使用 'top' 或 'htop' 检查 PID ${TASK_PID} 是否正在核心 ${EXCLUSIVE_CORE} 上运行。"
  36. echo "要停止任务,请运行:kill ${TASK_PID}"
复制代码
std::enable_if 作为模板默认参数
除了返回类型,std::enable_if也可作为模板的默认参数,语法更简洁:
  1. lscpu -e    # 假设输出显示 CPU 0 和 CPU 8 都属于 CORE 0。这意味着它们是同一个物理核心上的两个“兄弟”逻辑核心。
  2. # 查看 CPU 8 的在线状态 (1 代表在线)
  3. cat /sys/devices/system/cpu/cpu8/online
  4. # 将 CPU 8 设置为离线 (禁用)
  5. echo 0 > /sys/devices/system/cpu/cpu8/online
  6. # 查看在线的CPU数量,会比原来少1
  7. nproc
  8. # 或者再次运行 lscpu,会看到 CPU 8 显示为 no (离线)
  9. lscpu -e | grep "cpu8"
  10. # 此时,操作系统调度器不会再向 CPU 8 分配任何任务。CPU 0 现在可以不受干扰地使用物理核心 0 的全部资源。
  11. #重启只需
  12. echo 1 > /sys/devices/system/cpu/cpu8/online
复制代码
Concepts(C++20)显式定义模板参数的约束,替代部分std::enable_if的复杂逻辑,使代码更易读。
  1. # 清晰地列出CPU、核心、Socket的对应关系
  2. lscpu -e=CPU,CORE,SOCKET
  3. # 绑定策略进程到物理核8-15(跳过超线程核)
  4. taskset -c 8-15 ./strategy_engine
复制代码
9. 分支预测提示
直接在代码中告诉编译器哪个分支更有可能执行,帮助旧微架构生成更优的指令布局。在现代处理器上使用这些分支前缀会生成有效的 x86/x64 汇编,但可能不会在现代处理器上产生性能提升。

  • GCC/Clang 扩展:
[code]// 使用#pragma once确保头文件只被包含一次,防止重复包含#pragma once#include #include // LIKELY 宏定义,用于告诉编译器条件表达式 x 为真的可能性很大// __builtin_expect 是 GCC 和 Clang 等编译器提供的内建函数// 它接受两个参数,第一个参数是一个表达式,第二个参数是期望的值// 这里将!!(x) 作为表达式,1 作为期望的值,表示 x 为真的可能性很大// !! 是双重逻辑非运算符,用于将 x 转换为布尔值#define LIKELY(x) __builtin_expect(!!(x), 1)// UNLIKELY 宏定义,用于告诉编译器条件表达式 x 为真的可能性很小// 同样使用 __builtin_expect 内建函数,将!!(x) 作为表达式,0 作为期望的值// 表示 x 为真的可能性很小#define UNLIKELY(x) __builtin_expect(!!(x), 0)// ASSERT 函数,用于在条件不满足时输出错误信息并终止程序// 使用 UNLIKELY 宏来标记条件判断,表明条件不成立的情况是很少发生的// 如果条件不成立,会输出错误信息到标准错误输出流,并调用 exit 函数终止程序inline auto ASSERT(bool cond, const std::string &msg) noexcept {    if (UNLIKELY(!cond)) {        std::cerr

相关推荐

您需要登录后才可以回帖 登录 | 立即注册