跳到正文

PandaCore · 自研内核

更快。更轻。更高效每一台设备都能用。

PandaCore 是 PandaFan 为客户端开发的核心引擎。我们用开源测试工具 tun-bench,在同一台 Mac 上把它与两款业界性能领先的开源内核放在一起测吞吐、CPU 与内存。

这些对照只为帮助你了解 PandaFan 的底层引擎,回环测试仅代表性能上限,现实意义有限。我们尊重开源社区,也在不定期赞助开源项目。感谢每一位贡献者的努力。

同样 10 秒,实测速率回放。

TUN 模式 · 单条 TCP 下载 · 三轮中位数

0.0×

单条 TCP 上传

对开源内核 2 · 32.9 vs 2.6 Gbit/s

1.2× · 对开源内核 1

0.0×

单条 TCP 下载

对开源内核 2 · 29.2 vs 3.0 Gbit/s

1.1× · 对开源内核 1

−0%

1000 条连接时的内存

对开源内核 2 · 20 vs 95 MiB

−14% · 对开源内核 1

−0%

单条下载时每 Gbit 的 CPU

对开源内核 2 · 3.27 vs 39.64 %/Gbit

−7% · 对开源内核 1

吞吐

上传更快,下载更快。

在同一台 M1 Mac mini 上进行三轮对照,第二轮反转内核顺序。上传、下载各测单条流和 8 条流,并增加 1 Gbit/s 限速档;每格 5 秒,预热 1 秒。以下均为各项指标的三轮中位数。

Mac mini · Apple M1 · macOS 26.5.1 · MTU 4064

上传 · 单条流

12.7×对开源内核 2

1.2×对开源内核 1

32.927.32.6Gbit/s

下载 · 单条流

9.7×对开源内核 2

1.1×对开源内核 1

29.227.33.0Gbit/s

上传 · 8 条流

10.4×对开源内核 2

平手对开源内核 1

20.219.41.9Gbit/s

下载 · 8 条流

3.0×对开源内核 2

平手对开源内核 1

18.117.46.1Gbit/s

完整矩阵对两款内核:38 项领先 · 8 项平手 · 0 项落后

相差不到 5% 记为平手;统计覆盖 6 档吞吐、6 档 CPU/Gbit、6 档能耗/Gbit 和 5 档内存,各对照两款内核。中位数不代表每一轮都领先。

完整对照数据23 格

23 项指标分别对照两款内核,共 46 项比较。每个数字为三轮中位数,CPU/Gbit 与能耗/Gbit 先逐轮计算再取中位数。下载包含生成数据和未经删选的原始轮次。

测试项PandaCore开源内核 1开源内核 2对比
越高越好上传 · 单条流Gbit/s32.8727.292.5812.7× · 对开源内核 2+1174% · PandaCore 领先1.2× · 对开源内核 1+20% · PandaCore 领先
上传 · 8 条流Gbit/s20.1819.431.9410.4× · 对开源内核 2+938% · PandaCore 领先1.0× · 对开源内核 1+4% · 平手
上传 · 1 Gbit/sGbit/s0.990.991.001.0× · 对开源内核 10% · 平手1.0× · 对开源内核 20% · 平手
下载 · 单条流Gbit/s29.1827.303.019.7× · 对开源内核 2+870% · PandaCore 领先1.1× · 对开源内核 1+7% · PandaCore 领先
下载 · 8 条流Gbit/s18.1217.446.083.0× · 对开源内核 2+198% · PandaCore 领先1.0× · 对开源内核 1+4% · 平手
下载 · 1 Gbit/sGbit/s0.990.991.001.0× · 对开源内核 10% · 平手1.0× · 对开源内核 20% · 平手
越低越好CPU · 上传 · 单条流%/Gbit2.973.5598.2433.0× · 对开源内核 2−97% · PandaCore 领先1.2× · 对开源内核 1−16% · PandaCore 领先
CPU · 上传 · 8 条流%/Gbit4.754.91170.1135.8× · 对开源内核 2−97% · PandaCore 领先1.0× · 对开源内核 1−3% · 平手
CPU · 上传 · 1 Gbit/s%/Gbit24.3828.11150.126.2× · 对开源内核 2−84% · PandaCore 领先1.2× · 对开源内核 1−13% · PandaCore 领先
CPU · 下载 · 单条流%/Gbit3.273.5239.6412.1× · 对开源内核 2−92% · PandaCore 领先1.1× · 对开源内核 1−7% · PandaCore 领先
CPU · 下载 · 8 条流%/Gbit5.455.6764.3411.8× · 对开源内核 2−92% · PandaCore 领先1.0× · 对开源内核 1−4% · 平手
CPU · 下载 · 1 Gbit/s%/Gbit27.8131.2477.732.8× · 对开源内核 2−64% · PandaCore 领先1.1× · 对开源内核 1−11% · PandaCore 领先
越低越好能耗 · 上传 · 单条流J/Gbit0.089020.113321.2940914.5× · 对开源内核 2−93% · PandaCore 领先1.3× · 对开源内核 1−21% · PandaCore 领先
能耗 · 上传 · 8 条流J/Gbit0.114450.139701.1990910.5× · 对开源内核 2−90% · PandaCore 领先1.2× · 对开源内核 1−18% · PandaCore 领先
能耗 · 上传 · 1 Gbit/sJ/Gbit0.015500.017242.07201134× · 对开源内核 2−99% · PandaCore 领先1.1× · 对开源内核 1−10% · PandaCore 领先
能耗 · 下载 · 单条流J/Gbit0.088230.101990.9494910.8× · 对开源内核 2−91% · PandaCore 领先1.2× · 对开源内核 1−13% · PandaCore 领先
能耗 · 下载 · 8 条流J/Gbit0.099070.111840.735357.4× · 对开源内核 2−87% · PandaCore 领先1.1× · 对开源内核 1−11% · PandaCore 领先
能耗 · 下载 · 1 Gbit/sJ/Gbit0.017660.018840.7850444.5× · 对开源内核 2−98% · PandaCore 领先1.1× · 对开源内核 1−6% · PandaCore 领先
越低越好内存 · 空闲MiB · physical_footprint9.4412.4213.801.5× · 对开源内核 2−32% · PandaCore 领先1.3× · 对开源内核 1−24% · PandaCore 领先
内存 · 250 条连接MiB · physical_footprint12.5016.8135.812.9× · 对开源内核 2−65% · PandaCore 领先1.3× · 对开源内核 1−26% · PandaCore 领先
内存 · 500 条连接MiB · physical_footprint15.1118.9255.003.6× · 对开源内核 2−73% · PandaCore 领先1.3× · 对开源内核 1−20% · PandaCore 领先
内存 · 750 条连接MiB · physical_footprint17.6420.4773.954.2× · 对开源内核 2−76% · PandaCore 领先1.2× · 对开源内核 1−14% · PandaCore 领先
内存 · 1000 条连接MiB · physical_footprint20.2423.6695.114.7× · 对开源内核 2−79% · PandaCore 领先1.2× · 对开源内核 1−14% · PandaCore 领先

内存、CPU 与能耗

更少的内存,更省的 CPU。

从空闲到 1000 条连接,记录每一步内存占用。CPU 和能耗均按传输量归一化,覆盖全速与 1 Gbit/s 限速档,让不同速率下的结果可比。

内存

0–1000 条连接的内存占用

MiB · 越低越好

空闲时内存 −32%(对开源内核 2),1000 条连接时 −79%(对开源内核 2)。

CPU · 全速与限速

每 Gbit/s 的 CPU 占用

%/Gbit · 越低越好

8 条流全速时每 Gbit/s 的 CPU:下载 −92%(对开源内核 2),上传 −97%(对开源内核 2);PandaCore 下载 5.5%,开源内核 2 64.3%。

进程能耗 · 全速

每 Gbit 的 CPU 能耗估算

J/Gbit · 越低越好

单条流全速时进程 CPU 能耗/Gbit:下载 −91%,上传 −93%(对开源内核 2)。这不是整机耗电或电池续航测量。

进程能耗 · 1 Gbit/s 限速

相同速率下的能耗

J/Gbit · 越低越好

三款内核均达到约 0.99–1.00 Gbit/s。按实际传输量比较进程 CPU 能耗,数值越低越好;不代表整机功耗。

以上是本机回环测试,流量从 TUN 进内核再回到本机服务端,反映的是内核本身的上限。测试结果会因设备、系统版本和后台负载而不同;实际网速还取决于线路、协议与服务器。

客户端

强大的内核,简单的客户端。

速度是基础,简单是日常。

未连接

一触即连

登录,轻点一下,即刻连接。线路自动优选,无需研究。

智能分流

国内网站直连,国外网站经由 PandaFan。规则内置并持续更新,你自定义的规则始终生效。

增强模式

一个开关,电脑或手机上的所有应用流量即全部经由 PandaFan,无需逐个设置。

兼容 · 免费

配置照旧。内核免费。

PandaCore 读取与 mihomo 相同的 YAML 配置。内核程序本身免费下载,无需 PandaFan 账号即可运行。

三条命令,即刻体验
# 下载(Linux x86_64)
curl -fL https://build.bamboe.app/panda-core/latest/pandacore-linux-amd64 -o pandacore && chmod +x pandacore
# 检查现有配置
./pandacore -f config.yaml -t
INFOpanda_config: Config loaded: mode=rule, proxies=6, rules=3
INFOpandacore: Configuration test passed
# 启动
./pandacore -f config.yaml
INFOpandacore: panda-core is running
INFOpanda_listener::mixed: Mixed listener 'mixed' on 127.0.0.1:7890
INFOpanda_api: REST API listening on 127.0.0.1:9090
  • 现有配置,直接可用

    节点、策略组、分流规则、DNS 与 TUN,均按 mihomo 的写法读取。启动前加上 -t,即可先行检查。

  • 控制接口,完全一致

    对外接口与 mihomo 相同,现有的控制面板与工具可直接连接。

  • 免费,无需账号

    下载即可运行自己的配置。接入 PandaFan 账号,只需一条 login 命令。

  • 个别协议如 Shadowsocks、VMess、Snell、SSH 不提供支持,需要从配置中剔除。

测试方法

我们如何测试

所有公开指标来自 tun-bench。同一台 Mac、TCP/IPv4 直连 TUN 回环、相同 MTU,三款内核依次运行三轮,第二轮反转顺序,轮间冷却 30 秒。各指标独立取三轮中位数,所有轮次都计入。

tun-bench 创建 TUN 网卡,用 iperf3 将流量送进被测内核,再转发回本机服务端。上传和下载各测单条流、8 条流全速及单条流 1 Gbit/s 限速。

CPU 为进程累计 CPU 时间除以传输量;macOS 能耗来自 proc_pid_rusage 的进程 CPU 能耗估算。内存按 0、250、500、750、1000 条空闲连接记录 physical footprint,不是 RSS。

结果仅适用于本次 M1 Mac mini 的 TUN 回环测试,不能外推为所有设备、协议或每一轮均领先。被测二进制报告版本 1.9.2,相关优化已随 1.9.3 发布;这里并非对 1.9.3 发布包的重新测量。实际网速还取决于线路、协议与服务器。

测试日期
2026-09-19
汇总方式
每项 3 轮,逐项取中位数
测试机
Mac mini · Apple M1 · macOS 26.5.1
测试工具
tun-bench · 201b780
PandaCore
1.9.2 + macOS optimizations (shipped in 1.9.3)
开源内核 1
1.15.0-alpha.4
开源内核 2
1.19.31 · gvisor
MTU
4064
吞吐条件
每格 5 秒,预热 1 秒,8 个工作线程
内存条件
每步 250 条空闲连接,直到 1000 条,每条 64 字节负载
负载口径
进程 CPU 时间与 CPU 能耗估算(非整机耗电)

自己复测

用同一份 tun-bench 配置就能在你自己的机器上重跑这组对照。tun-bench 原生支持两款开源内核,驱动 PandaCore 需要打一个小补丁。

sudo ./tun-bench run tun-bench-darwin.yml
配置内容tun-bench-darwin.yml · 36 行
# tun-bench matrix behind the macOS numbers on pandafan.app/pandacore (SagerNet/tun-bench, run as root).
# Point `version` at your PandaCore binary: an absolute path is used as a local build, while tun-bench
# downloads the open-source engines itself. Run three rounds with reversed implementation order in
# round two and a 30-second cooldown between rounds; retain all rounds and aggregate by median.
environments:
  darwin:
    type: local
    os: darwin

implementations:
  pandacore:
    type: mihomo
    version: /usr/local/bin/pandacore
  sing-box:
    type: sing-box
    version: 1.15.0-alpha.4
  mihomo:
    type: mihomo
    version: 1.19.31

matrix:
  - name: typical
    implementation: [ pandacore, sing-box, mihomo ]
    ip: [ 4 ]
    network: [ tcp ]
    stack: [ pandacore/panda, sing-box/go, mihomo/gvisor ]
    mtu: [ 4064 ]
    include:
      - bitrate: 0
      - parallel: 8
      - bitrate: 1Gbps
  - name: memory
    type: memory
    implementation: [ pandacore, sing-box, mihomo ]
    stack: [ pandacore/panda, sing-box/go, mihomo/gvisor ]
    mtu: [ 4064 ]
    ip: [ 4 ]
    network: [ tcp ]
补丁内容tun-bench-pandacore.patch · 103 行

补丁让 tun-bench 把本地路径当作 PandaCore 二进制、按 PandaCore 的配置格式写 TUN 段,并把测试网段挪到不与 PandaCore 默认地址冲突的位置。

diff --git a/artifacts.go b/artifacts.go
index 112f4e2..791ba40 100644
--- a/artifacts.go
+++ b/artifacts.go
@@ -137,7 +137,10 @@ func (p *artifactPreparer) binary(ctx context.Context, software, version, source
 		return binary, unsupported
 	}
 	var err error
-	if sourcePackage != "" {
+	if sourcePackage == "" && filepath.IsAbs(version) {
+		// A version given as an absolute path is a locally built executable: use it as is.
+		binary.path, binary.version = version, "local"
+	} else if sourcePackage != "" {
 		directory, createErr := os.MkdirTemp(p.directory, "package-*")
 		if createErr != nil {
 			return binary, createErr
diff --git a/benchmark.go b/benchmark.go
index ef4297c..b5ecaba 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -391,12 +391,28 @@ func (b *benchmark) startSubject(ctx context.Context, probePort int) error {
 		} else {
 			listener["inet4-address"] = []string{b.environment.address.String()}
 		}
-		content, err = yaml.Marshal(map[string]any{
+		document := map[string]any{
 			"mode": "rule", "log-level": "warning", "ipv6": true, "find-process-mode": "off",
 			"listeners": []any{listener},
 			"proxies":   []any{map[string]any{"name": "relay", "type": "socks5", "server": relayAddress, "port": relayPort, "udp": true}},
 			"rules":     []string{"MATCH,relay"}, "dns": map[string]any{"enable": false},
-		})
+		}
+		if strings.Contains(filepath.Base(b.options.executable), "pandacore") {
+			// pandacore takes mihomo's CLI and YAML but declares the TUN in the top-level `tun:` section.
+			delete(document, "listeners")
+			// pandacore forwards the benchmark target directly, like sing-box: the TUN rewrites the
+			// target address to loopback (destination-override) and the rule sends it to DIRECT, so no
+			// SOCKS5 hop is measured. Its preflight wants the host default route; outbound binding skips
+			// loopback destinations.
+			document["tun"] = map[string]any{
+				"enable": true, "device": b.environment.interfaceName, "stack": stack, "mtu": b.options.MTU,
+				"auto-route": false, "auto-detect-interface": true,
+				"destination-override": map[string]any{b.environment.target.String(): b.options.loopback()},
+			}
+			document["rules"] = []string{"IP-CIDR," + targetPrefix + ",DIRECT,no-resolve", "MATCH,DIRECT"}
+			document["log-level"] = "info" // keep the TUN driver lines visible when the interface never appears
+		}
+		content, err = yaml.Marshal(document)
 		path = filepath.Join(b.directory, "mihomo.yaml")
 		args = []string{"-f", path, "-d", b.directory}
 	case "v2ray", "xray":
diff --git a/configuration.go b/configuration.go
index d9107ef..00eba19 100644
--- a/configuration.go
+++ b/configuration.go
@@ -273,7 +273,7 @@ func readConfiguration(path, matrixName, measurementType string) (runConfigurati
 			}
 			implementation.Version = strings.TrimPrefix(implementation.Version, "v")
 			if implementation.Version != "" {
-				if implementation.Version != "latest" && !semver.IsValid("v"+implementation.Version) {
+				if implementation.Version != "latest" && !filepath.IsAbs(implementation.Version) && !semver.IsValid("v"+implementation.Version) {
 					return configuration, nil, E.New(name, ": invalid release version ", implementation.Version)
 				}
 			} else if implementation.Package != "" && !filepath.IsAbs(implementation.Package) {
diff --git a/network.go b/network.go
index 4aa15e2..ff3172f 100644
--- a/network.go
+++ b/network.go
@@ -18,8 +18,8 @@ import (
 var errUDPPayloadIntegrity = E.New("UDP payload integrity failure")
 
 func prepareNetwork(ctx context.Context, configuration benchmarkOptions, placement *environment) error {
-	placement.address = netip.MustParsePrefix("198.18.0.1/29")
-	placement.target = netip.MustParseAddr("198.18.0.3")
+	placement.address = netip.MustParsePrefix("198.19.0.1/29")
+	placement.target = netip.MustParseAddr("198.19.0.3")
 	if configuration.IP == 6 {
 		placement.address = netip.MustParsePrefix("fd00::1/125")
 		placement.target = netip.MustParseAddr("fd00::3")
@@ -30,7 +30,7 @@ func prepareNetwork(ctx context.Context, configuration benchmarkOptions, placeme
 	}
 	subnets := []netip.Prefix{placement.address.Masked()}
 	if configuration.software == "leaf" && configuration.IP == 6 {
-		subnets = append(subnets, netip.MustParsePrefix("198.18.0.0/29"))
+		subnets = append(subnets, netip.MustParsePrefix("198.19.0.0/29"))
 	}
 	for _, subnet := range subnets {
 		for _, prefix := range routes {
diff --git a/platform_linux.go b/platform_linux.go
index 227cc0d..3546b50 100644
--- a/platform_linux.go
+++ b/platform_linux.go
@@ -209,6 +209,10 @@ func prepareInterface(configuration benchmarkOptions, placement environment, net
 		return false, nil
 	}
 	queues, err := filepath.Glob(filepath.Join("/sys/class/net", placement.interfaceName, "queues/tx-*"))
+	if strings.Contains(filepath.Base(configuration.executable), "pandacore") {
+		// pandacore always opens its multi-queue TUN with its own lane count; accept whatever it created.
+		return len(queues) >= 1, err
+	}
 	return len(queues) == configuration.queues, err
 }
 

七种设备。同一颗内核。

PandaCore 内置于每一个官方客户端,行为一致,同步更新。轻点平台名称即可前往下载。

  • 一个账号,覆盖所有设备,无需重复购买。
  • 客户端自动更新,内核的每一次改进如期而至。
  • 客服全天候在线,随时为你解答。

现在,开始尝试。

注册,下载客户端,登录即用。手机、平板、电脑,一个账号。

查看价格