# c-js-lua-wasm-cmp **Repository Path**: yorkjia/c-js-lua-wasm-cmp ## Basic Information - **Project Name**: c-js-lua-wasm-cmp - **Description**: c、JS、lua、wasm 语言对比 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-05 - **Last Updated**: 2026-03-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # c-js-lua-wasm-cmp 跨平台 C、JavaScript(QuickJS)、Lua 和 WebAssembly(WAMR) 四语言性能对比基准测试框架。 ## 1. 工程概述 ### 1.1 项目目标 构建一个跨平台的 C、JavaScript(QuickJS)、Lua(官方) 和 WebAssembly(WAMR) 四语言性能对比基准测试框架,支持在 Ubuntu 开发环境本地执行,并能交叉编译到嵌入式 ARM 平台运行,为嵌入式系统选择合适的脚本语言/扩展语言提供量化数据支持。 更具体的需求和目标请查看 [project_desc.md](project_desc.md) 和 [todo0305.md](todo0305.md)。 --- ## 2. 工程实现原理 ### 2.1 整体架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ main.c │ │ (命令行解析、多运行时选择、结果输出) │ ├─────────────────────────────────────────────────────────────────┤ │ config.h/c │ test_registry.h/c │ runner.h/c │ │ (配置管理) │ (测试注册发现) │ (执行器) │ ├─────────────────────────────────────────────────────────────────┤ │ runners/ │ │ ┌─────────────┬─────────────┬─────────────┬─────────────┐ │ │ │ quickjs_ │ lua_ │ wamr_ │ c_ │ │ │ │ runner.c │ runner.c │ runner.c │ runner.c │ │ │ └─────────────┴─────────────┴─────────────┴─────────────┘ │ ├─────────────────────────────────────────────────────────────────┤ │ tests/ │ │ perf_fibonacci.c │ perf_sieve.c │ perf_matrix.c │ ... │ ├─────────────────────────────────────────────────────────────────┤ │ common/ │ │ benchmark.h/c (时间/内存测量) │ result.h/c (统计计算) │ ├─────────────────────────────────────────────────────────────────┤ │ utils/ │ │ json_output.c │ csv_output.c │ console.c │ └─────────────────────────────────────────────────────────────────┘ ``` ### 2.2 核心模块实现 #### 2.2.1 测量模块 (`src/common/`) **时间测量** - 使用 `clock_gettime(CLOCK_MONOTONIC)` 实现微秒级精度: ```c void benchmark_start(benchmark_time_t *time) { clock_gettime(CLOCK_MONOTONIC, &time->ts); getrusage(RUSAGE_SELF, &time->usage); } void benchmark_end(const benchmark_time_t *start, benchmark_result_t *result) { struct timespec end; clock_gettime(CLOCK_MONOTONIC, &end); result->elapsed_us = timespec_diff_us(&end, &start->ts); // 计算 CPU 时间差... } ``` **内存测量** - 通过 `/proc/self/status` 获取: ```c long benchmark_get_memory_rss(void) { // 解析 /proc/self/status 中的 VmRSS 字段 } ``` #### 2.2.2 测试注册系统 (`src/core/test_registry.h/c`) 使用静态数组存储测试用例,支持按 ID 查找和按套件枚举: ```c typedef struct { const char *id; // 测试 ID (如 "PERF-001") const char *name; // 测试名称 const char *description; // 测试描述 test_suite_t suite; // 所属套件 int (*func_c)(void); // C 语言实现 int (*func_js)(void); // JavaScript 实现 int (*func_lua)(void); // Lua 实现 int (*func_wasm)(void); // WebAssembly 实现 } test_case_t; ``` 每个测试文件使用 `__attribute__((constructor))` 自动注册: ```c __attribute__((constructor)) void perf_fibonacci_init(void) { test_registry_register(&g_test_recursive); test_registry_register(&g_test_iterative); } ``` #### 2.2.3 运行时封装 (`src/runners/`) **QuickJS 运行时** - 使用 GLOBAL 模式执行脚本,通过 `globalThis` 导出函数: ```c // 执行脚本 JSValue result = JS_Eval(ctx, script, size, script_path, JS_EVAL_TYPE_GLOBAL); // 从 globalThis 获取函数 JSValue global = JS_GetGlobalObject(ctx); JSValue func_obj = JS_GetPropertyStr(ctx, global, func_name); // 调用函数 JS_Call(ctx, func_obj, global, 0, NULL); ``` **Lua 运行时** - 使用 `luaL_loadfile` 加载脚本,直接调用全局函数: ```c luaL_loadfile(L, script_path); lua_pcall(L, 0, LUA_MULTRET, 0); // 执行脚本定义函数 lua_getglobal(L, func_name); // 获取函数 lua_pcall(L, 0, 0, 0); // 调用函数 ``` **WAMR 运行时** - 使用 WebAssembly C API 加载和执行 WASM 模块: ```c // 创建引擎和存储 wasm_engine_new(); wasm_store_new(engine); // 加载 WASM 文件 wasm_module_new(store, &wasm_bytes); // 创建实例并调用导出函数 wasm_instance_new(store, module, &imports, NULL); wasm_instance_exports(instance, &exports); wasm_func_call(func, &args, &results); ``` #### 2.2.4 执行器 (`src/core/runner.c`) 执行流程: 1. 初始化运行时(QuickJS/Lua/WAMR) 2. 执行预热轮次(不记录结果) 3. 执行正式测试轮次,记录每次的时间/内存样本 4. 计算统计值(平均值、标准差、P50/P90/P99) ```c int runner_run_test(runner_context_t *ctx, const test_case_t *test_case, test_statistics_t *stats) { // 预热轮次 for (int i = 0; i < warmup_rounds; i++) { run_script_with_runtime(...); } // 正式测试轮次 for (int i = 0; i < rounds; i++) { benchmark_start(&start_time); run_script_with_runtime(...); benchmark_end(&start_time, &sample); // 记录样本... } // 计算统计值 result_add_samples(stats, samples, count); result_compute_statistics(stats); } ``` #### 2.2.5 统计计算 (`src/common/result.c`) 支持以下统计指标: - 平均值、标准差 - 最小值、最大值 - 百分位数 P50/P90/P99 ```c void result_compute_statistics(test_statistics_t *stats) { // 计算平均值 stats->time_avg = (double)sum / count; // 计算标准差 stats->time_stddev = sqrt(sum_sq / count - avg * avg); // 排序后计算百分位数 stats->p50 = result_percentile(sorted, count, 50); stats->p90 = result_percentile(sorted, count, 90); stats->p99 = result_percentile(sorted, count, 99); } ``` --- ## 3. 构建与安装 ### 3.1 前置要求 - Ubuntu 22.04 (x86_64) - CMake 3.16+ - GCC 10+ / Clang 12+ ### 3.2 第三方库路径 运行时库位于 `/opt/ctools/` 目录: - QuickJS: `/opt/ctools/QuickJS/` - Lua: `/opt/ctools/lua-5.4.6/src/` - WAMR: `/opt/ctools/wasm-micro-runtime/` ### 3.3 WASM 编译 使用 WASI SDK 编译 C 代码为 WASM 文件: ```bash # 编译 WASM 文件 /opt/ctools/wasi-sdk-24.0-x86_64-linux/bin/clang \ --sysroot=/opt/ctools/wasi-sdk-24.0-x86_64-linux/share/wasi-sysroot \ fibonacci_wasm.c \ -o fibonacci.wasm \ -Wl,--export=run -Wl,--no-entry -nostartfiles -O2 ``` ### 3.4 构建命令 ```bash # 本地开发构建(Release) ./scripts/build.sh # Debug 构建 ./scripts/build.sh debug # 清理 ./scripts/build.sh clean ``` ### 3.5 手动构建 ```bash mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. cmake --build . ``` --- ## 4. 测试方法 ### 4.1 基本用法 ```bash # 列出所有可用测试 ./build/benchmark_runner --list # 运行 C 语言基准测试 ./build/benchmark_runner --test PERF-001 --rounds 3 # 运行 JavaScript 测试 ./build/benchmark_runner --runtime js --script fibonacci --test PERF-001 --rounds 3 # 运行 Lua 测试 ./build/benchmark_runner --runtime lua --script fibonacci --test PERF-001 --rounds 3 # 运行 WASM 测试(需要 .wasm 文件) ./build/benchmark_runner --runtime wasm --script fibonacci --test PERF-001 --rounds 3 ``` ### 4.2 命令行参数 | 参数 | 说明 | 默认值 | |------|------|--------| | `-r, --rounds NUM` | 测试轮数 | 10 | | `-w, --warmup NUM` | 预热轮数 | 3 | | `-t, --timeout MS` | 超时时间 (毫秒) | 30000 | | `-f, --format FMT` | 输出格式 (json/csv/console) | console | | `-o, --output FILE` | 输出文件路径 | - | | `-s, --suite NAME` | 测试套件 (perf/mem/start/embed) | - | | `-i, --test ID` | 单个测试 ID | - | | `-d, --script-dir DIR` | 脚本目录 | ./test_scripts | | `-R, --runtime RT` | 运行时类型 (c/js/lua/wasm) | c | | `-S, --script FILE` | 脚本文件名(不含扩展名) | - | | `-v, --verbose` | 详细输出 | 关闭 | | `-l, --list` | 列出可用测试 | - | | `-h, --help` | 显示帮助 | - | ### 4.3 输出格式 **Console(控制台)** - 摘要表格: ``` ================================================================================ BENCHMARK SUMMARY ================================================================================ ID Name Language Avg(μs) Min(μs) Max(μs) ------------ -------------------- ------------ ---------- ---------- ---------- PERF-001 fibonacci_recursive c 2582704.67 2568762 2595408 PERF-001 fibonacci_recursive lua 102377.33 99583 106218 PERF-001 fibonacci_recursive javascript 168386.00 168386 168386 ================================================================================ ``` **JSON** - 详细数据(使用 `-f json -o results.json`): ```json { "test_id": "PERF-001", "test_name": "fibonacci_recursive", "language": "javascript", "sample_count": 3, "time_avg": 168386.00, "time_min": 168386, "time_max": 168386, "p50": 168386, "p90": 168386, "p99": 168386 } ``` **CSV** - 便于电子表格分析(使用 `-f csv -o results.csv`) --- ## 5. 测试用例 ### 5.1 PERF 算法性能测试套件 | ID | 名称 | 目的 | 参数 | |----|------|------|------| | PERF-001 | fibonacci_recursive | 函数调用和递归性能 | n=30, 1000 次 | | PERF-001-I | fibonacci_iterative | 迭代算法性能 | n=30, 1000 次 | | PERF-002 | prime_sieve | 数组操作和循环性能 | limit=1,000,000 | | PERF-003 | matrix_multiply | 浮点计算和内存访问 | 100×100 矩阵 | | PERF-004 | quick_sort | 递归和比较操作 | 10,000 整数 | | PERF-005 | string_process | 字符串操作性能 | 1MB 文本 | ### 5.2 待实现测试套件 - **MEM 内存特性测试**:运行时内存占用、堆分配性能、大内存操作、内存泄漏检测 - **START 启动特性测试**:冷启动时间、热启动时间、脚本解析时间、模块加载时间 - **EMBED 嵌入式特性测试**:二进制大小、内存受限测试、实时性测试、能耗评估 --- ## 6. 初步测试结论 ### 6.1 斐波那契数列性能对比 (递归算法) #### 公平对比测试 (2026-03-08 更新) **测试条件**: fib(25) × 10 次迭代(所有语言相同) | 运行时 | 平均时间 (μs) | 内存 (KB) | CPU 时间 (μs) | CPU% | 相对性能 | 速度倍数 | |--------|--------------|-----------|--------------|------|----------|----------| | **C (GCC)** | **4,460** | 2,332 | 4,419 | 99.1% | **基准** | **20x** | | **WebAssembly (WAMR)** | **89,906** | 11,481 | 89,706 | 99.8% | 0.05x | 1.0x | | **Lua 5.4.6** | **112,143** | 2,520 | 111,880 | 99.8% | 0.04x | 0.8x | | **JavaScript (QuickJS)** | **156,912** | 2,875 | 156,871 | 100.0% | 0.03x | 0.57x | > **注意**: > 1. C 语言性能最强,比 WASM 快约 20 倍,比 Lua 快约 25 倍,比 QuickJS 快约 35 倍 > 2. CPU% 接近 100% 说明是纯计算密集型任务 > 3. WASM 内存显示较大是因为包含整个 WAMR 运行时(子进程峰值 RSS) #### 指标说明 | 指标 | 含义 | 测量方法 | |------|------|----------| | **平均时间** | 墙上时间(wall-clock time),从开始到结束的总耗时 | `clock_gettime(CLOCK_MONOTONIC)` | | **内存** | RSS 常驻内存,程序占用的物理内存 | `/proc/self/status` (VmRSS) | | **CPU 时间** | CPU 实际执行代码的时间(用户态 + 内核态) | `getrusage(RUSAGE_SELF)` | | **CPU%** | CPU 利用率 = CPU 时间/墙上时间 × 100% | 计算得出 | > **CPU% 解读**: 表示程序运行期间 CPU 的利用效率。100% 表示 CPU 一直在执行代码(计算密集型),远低于 100% 表示有大量等待(如 I/O 操作)。 ### 6.2 完整测试结果 (2026-03-08 更新) #### PERF-003: 矩阵乘法 (100×100) | 运行时 | 平均时间 (μs) | 内存 (KB) | CPU 时间 (μs) | CPU% | 相对性能 | |--------|--------------|-----------|--------------|------|----------| | **WebAssembly (WAMR)** | **~10,600** | ~2,400 | ~10,500 | ~99% | **1.0x** | | Lua 5.4.6 | ~45,600 | ~2,600 | ~45,500 | ~99% | 0.23x | | JavaScript (QuickJS) | ~144,200 | ~3,000 | ~144,000 | ~99% | 0.07x | #### PERF-004: 快速排序 (10,000 整数) | 运行时 | 平均时间 (μs) | 内存 (KB) | CPU 时间 (μs) | CPU% | 相对性能 | |--------|--------------|-----------|--------------|------|----------| | **Lua 5.4.6** | **~18,100** | ~2,700 | ~18,000 | ~99% | **1.0x** | | JavaScript (QuickJS) | ~44,300 | ~3,100 | ~44,000 | ~99% | 0.41x | | WebAssembly (WAMR)** | ~421,500 | ~2,500 | ~420,000 | ~99% | 0.04x | > **注意**: 快速排序测试中 Lua 表现优异。WASM 因递归深度大受栈空间限制影响较大。 #### PERF-005: 字符串处理 (1MB 文本) | 运行时 | 平均时间 (μs) | 内存 (KB) | CPU 时间 (μs) | CPU% | 相对性能 | |--------|--------------|-----------|--------------|------|----------| | **WebAssembly (WAMR)** | **~123,500** | ~2,600 | ~120,000 | ~97% | **1.0x** | | Lua 5.4.6 | ~785,900 | ~5,000 | ~780,000 | ~99% | 0.16x | | JavaScript (QuickJS) | ~7,768,900 | ~1,024* | ~7,700,000 | ~99% | 0.016x | > **注意**: JavaScript 因 1MB 内存限制导致性能严重下降。Lua 表现中等,WASM 保持最优。 > *JavaScript 内存被限制为 1MB,超出后性能急剧下降。 ### 6.3 综合性能排名 #### 公平对比(相同工作量) | 排名 | 运行时 | 斐波那契递归 | 矩阵乘法 | 快速排序 | 字符串处理 | 内存占用 | CPU 效率 | 综合评价 | |------|--------|-------------|----------|----------|------------|----------|---------|----------| | 🏆 | **C (GCC)** | ⭐⭐⭐ (4.5ms) | - | - | - | ⭐⭐⭐ (2.3MB) | ⭐⭐⭐ (99%) | 性能王者 | | 🥇 | **WebAssembly** | ⭐⭐ (90ms) | ⭐⭐⭐ (11ms) | ⭐ (422ms) | ⭐⭐⭐ (124ms) | ⭐⭐ (11.5MB)* | ⭐⭐⭐ (99%) | 数值计算强 | | 🥈 | **Lua 5.4.6** | ⭐⭐ (112ms) | ⭐⭐ (46ms) | ⭐⭐⭐ (18ms) | ⭐⭐ (786ms) | ⭐⭐⭐ (2.5MB) | ⭐⭐⭐ (99%) | 均衡表现 | | 🥉 | **JavaScript** | ⭐ (157ms) | ⭐ (144ms) | ⭐⭐ (44ms) | ⭐ (7769ms) | ⭐⭐⭐ (2.9MB) | ⭐⭐⭐ (100%) | 轻量级选择 | > **注**: > - 斐波那契测试为公平对比(相同工作量),其他测试为各自实现的最佳性能 > - *WASM 内存显示为子进程峰值 RSS,包含整个 WAMR 运行时,实际使用约 2-3MB > - CPU 效率都接近 100%,说明都是计算密集型任务 ### 6.4 关键发现 1. **C 语言性能最强** - 比其他语言快 20-35 倍,直接编译为机器码执行 2. **WASM 数值计算强** - 在矩阵乘法、字符串处理等批量计算中表现优异 3. **Lua 递归算法优异** - 在快速排序等递归算法中超出预期 4. **JavaScript 便利性最好** - 语法灵活,但受内存限制性能有影响 5. **CPU 效率都接近 100%** - 说明测试都是计算密集型任务,没有 I/O 等待 ### 6.5 内存占用分析 | 运行时 | 平均内存 (KB) | 说明 | |--------|--------------|------| | C (GCC) | ~2,300 | 基准,仅包含代码和数据 | | Lua | ~2,500 | 轻量级解释器,内存占用低 | | JavaScript | ~2,900 | QuickJS 引擎 + 1MB 内存限制 | | WASM | ~11,500* | 子进程峰值 RSS,包含整个 WAMR 运行时 | > **重要说明:WASM 内存测量方式** > > WASM 通过 `fork+exec` 调用 `iwasm` CLI 执行,内存测量使用的是子进程的 `ru_maxrss`(峰值 RSS),包含: > - iwasm 可执行文件本身(约 400KB) > - WAMR 运行时库(约 600KB) > - WASM 模块代码和数据(约 100-200KB) > - WASM 堆内存和栈空间(配置为 1MB 栈 + 16KB 堆) > - 其他运行时开销 > > **因此 WASM 的 11.5MB 不能直接与其他语言对比**。实际 WASM 模块运行时的内存占用约 2-3MB,但由于测量的是整个子进程的峰值内存,所以数值偏大。 > > 这种测量方式对于评估"在嵌入式系统中使用 WASM 需要多少总内存"是有参考价值的,但如果是比较"纯代码内存占用",则 WASM 的数据会偏高。 ### 6.6 测量指标说明 - **执行时间 (墙上时间)**: 从开始到结束的墙上时间(微秒),包含所有开销 - **内存使用 (RSS)**: 常驻内存大小,通过 `/proc/self/status` 获取 - **CPU 时间**: 用户态 + 内核态 CPU 时间,通过 `getrusage()` 获取 - **CPU 占用率**: CPU 时间/墙上时间 × 100%,表示 CPU 利用效率 - **统计可靠性**: 多轮测试取平均值,报告 P50/P90/P99 百分位数 --- ## 7. 已知问题与待办事项 ### 7.1 高优先级 - [x] 补全 matrix/sort/string 测试的 JS/Lua/WASM 脚本实现 - [x] 完善 WAMR 的栈空间配置(已添加 --stack-size=1048576) - [x] 添加 WASM 编译脚本(使用 WASI SDK) ### 7.2 中优先级 - [ ] 补全 MEM/START/EMBED 系列测试 - [ ] 优化 WAMR 执行方式(当前使用 popen 调用 iwasm CLI,有额外开销) - [ ] 添加内存泄漏检测 ### 7.3 低优先级 - [ ] Python 分析脚本 (`tools/analyze.py`) - [ ] HTML 报告生成器 - [ ] CI/CD 配置 --- ## 8. 扩展指南 ### 8.1 添加新测试用例 1. 在 `src/tests/` 创建新的测试文件: ```c // perf_example.c #include "../core/test_registry.h" static int test_example(void) { // 测试逻辑 return 0; } static test_case_t g_test = { .id = "PERF-XXX", .name = "example", .description = "Example test", .suite = SUITE_PERF, .func_c = test_example, }; __attribute__((constructor)) void perf_example_init(void) { test_registry_register(&g_test); } ``` 2. 在 `test_scripts/` 创建对应脚本(如 `example.js`, `example.lua`) 3. 重新编译运行 ### 8.2 添加新运行时 1. 在 `src/runners/` 创建新的运行时封装 2. 在 `runner.c` 的 `run_script_with_runtime()` 中添加分支 3. 在 `main.c` 的 `parse_runtime_type()` 中添加识别 --- ## 9. 参考资源 - [QuickJS 官方文档](https://bellard.org/quickjs/) - [Lua 5.4 参考手册](https://www.lua.org/manual/5.4/) - [WAMR 文档](https://github.com/bytecodealliance/wasm-micro-runtime) - [WASI SDK](https://github.com/WebAssembly/wasi-sdk) - [project_desc.md](project_desc.md) - 详细项目描述 - [todo0305.md](todo0305.md) - 开发日志和待办事项 --- **最后更新**: 2026-03-07 ### 测试结果更新时间 - 斐波那契递归测试:2026-03-07 - 矩阵乘法/快速排序/字符串处理测试:2026-03-07 - 测试环境:Ubuntu 22.04, x86_64 --- ## 10. 快速参考 (2026-03-07 现状总结) ### 10.1 一键测试命令 ```bash # 1. 构建项目 ./scripts/build.sh # 2. 列出所有测试 ./build/benchmark_runner --list # 3. 公平对比测试 (fib(25) × 10 次迭代) ./build/benchmark_runner --runtime c --script fibonacci_c_test --test PERF-001 --rounds 3 --warmup 1 ./build/benchmark_runner --runtime js --script fibonacci_js_test --test PERF-001 --rounds 3 --warmup 1 ./build/benchmark_runner --runtime lua --script fibonacci_lua_test --test PERF-001 --rounds 3 --warmup 1 ./build/benchmark_runner --runtime wasm --script fibonacci --test PERF-001 --rounds 3 --warmup 1 # 4. 完整工作量测试 ./build/benchmark_runner --test PERF-001 --rounds 3 # C 语言 1000 次迭代 ``` ### 10.2 核心性能数据速查 | 测试项目 | C (μs) | WASM (μs) | Lua (μs) | JS (μs) | C 优势倍数 | |----------|--------|-----------|----------|---------|------------| | 斐波那契 fib(25)×10 | **3,300** | 79,000 | 101,000 | 166,000 | **24-50 倍** | | 矩阵乘法 100×100 | - | **10,600** | 45,600 | 144,200 | - | | 快速排序 10K 整数 | - | **421,500** | 18,100 | 44,300 | - | | 字符串处理 1MB | - | **123,500** | 785,900 | 7,768,900 | - | ### 10.3 代码架构关键点 ``` src/ ├── main.c # 入口:解析--runtime/--script 参数,构建脚本路径 ├── core/ │ ├── runner.c # 核心:dlopen 加载 C 脚本,popen 调用 iwasm │ ├── config.c # 命令行参数解析 │ └── test_registry.c # 测试用例注册/发现 ├── runners/ │ ├── quickjs_runner.c # QuickJS 引擎封装 │ ├── lua_runner.c # Lua 状态管理 │ ├── wamr_runner.c # WAMR (调用 iwasm CLI) │ └── c_runner.c # C 语言基准接口 └── tests/ # 测试用例实现 (perf_*.c) test_scripts/ # 脚本文件 (.js/.lua/.wasm/.so) ├── fibonacci.js/lua/wasm.c/so ├── matrix.js/lua/wasm.c ├── sort.js/lua/wasm.c └── string.js/lua/wasm.c ``` **关键实现细节**: 1. C 脚本通过 `dlopen(".so", RTLD_LAZY|RTLD_LOCAL)` 动态加载 2. WASM 通过 `popen("iwasm --stack-size=1048576 -f run xxx.wasm")` 执行 3. QuickJS/Lua 直接嵌入进程内执行 4. 所有运行时统一通过 `run()` 函数入口 ### 10.4 当前状态清单 - [x] 四语言公平对比测试完成 - [x] PERF-001/003/004/005 测试脚本补全 - [x] WASM 编译流程验证 (WASI SDK) - [x] README 文档更新 - [ ] MEM/START/EMBED 测试套件 - [ ] Python 分析工具 - [ ] CI/CD 配置