From 85b89b6e8d86f381d7933c5302fa98936d66fdff Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 12 Oct 2026 15:06:50 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=94=B9=E5=90=8D=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=20TransPyV=20->=20ViperC=EF=BC=88=E6=BA=90=E7=A0=81/=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=86=85=E7=9A=84=E7=BA=AF=E6=9B=BF=E6=8D=A2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ViperAIChat/project.vpj | 2 +- ViperCPW/project.vpj | 2 +- ViperFLProject/App/main2.vp | 4 +- ViperFLProject/project.vpj | 2 +- ViperMNIST/App/main.vp | 586 +++++++++++++++---------------- ViperMNIST/project.vpj | 2 +- ViperOpenSSLProject/project.vpj | 2 +- ViperQtHelloWorld/project.vpj | 2 +- ViperQtProject/App/main.vp | 2 +- ViperQtProject/project.vpj | 2 +- ViperRequestsTest/project.vpj | 2 +- ViperSpeedBenchmark/README.md | 4 +- ViperSpeedBenchmark/project.vpj | 2 +- ViperSpeedBenchmark/run_bench.py | 10 +- ViperTestProject/project.vpj | 2 +- ViperZipfileProject/project.vpj | 2 +- 16 files changed, 314 insertions(+), 314 deletions(-) diff --git a/ViperAIChat/project.vpj b/ViperAIChat/project.vpj index ef5ea60..345cd13 100644 --- a/ViperAIChat/project.vpj +++ b/ViperAIChat/project.vpj @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Desktop chat client: vqt6 GUI, requests(https) for network, json for parsing responses", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperCPW/project.vpj b/ViperCPW/project.vpj index 672529d..3079116 100644 --- a/ViperCPW/project.vpj +++ b/ViperCPW/project.vpj @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Standalone Viper repro for CreateProcessA returning 0 / GetLastError=87", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperFLProject/App/main2.vp b/ViperFLProject/App/main2.vp index b9d6bc9..0ebfba2 100644 --- a/ViperFLProject/App/main2.vp +++ b/ViperFLProject/App/main2.vp @@ -1,9 +1,9 @@ # main2.vp — ViperFLProject fltk GUI 测试(回调 + 控件展示) # -# 构建需 TPV/TPC 支持 project.vpj linker.static_libs 静态链接 +# 构建需 VPC/TPC 支持 project.vpj linker.static_libs 静态链接 # (本工程已配置链接 ../includes/fltk/cfltk/build 下的 cfltk2 + FLTK 静态库)。 # -# 回调说明:Viper 模块级函数可直接作为 Fl_Callback 传入(TPV 自动把函数名 +# 回调说明:Viper 模块级函数可直接作为 Fl_Callback 传入(VPC 自动把函数名 # bitcast 为函数指针)。回调签名统一为 def cb(w: bytes, data: bytes), # 其中 w 是触发回调的控件指针,data 是注册时传入的用户数据。 import t, c diff --git a/ViperFLProject/project.vpj b/ViperFLProject/project.vpj index 89d6fb5..78ae5a5 100644 --- a/ViperFLProject/project.vpj +++ b/ViperFLProject/project.vpj @@ -2,7 +2,7 @@ "name": "ViperFLProject - FLTK GUI Test", "version": "1.0.0", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperMNIST/App/main.vp b/ViperMNIST/App/main.vp index cd8bcc0..5393c76 100644 --- a/ViperMNIST/App/main.vp +++ b/ViperMNIST/App/main.vp @@ -1,293 +1,293 @@ -# -*- coding: utf-8 -*- -# ============================================================ -# ViperMNIST - 28x28 手写数字识别(MLP / CNN, torch-lite) -# -# 入口分发: -# * 无命令行参数 → 启动 Qt6 图形面板(数据/训练/推理, 含 3D 网络图) -# * 带命令行参数 → 走原 CLI(train / use) -# -# CLI 用法: -# app.exe --mode train --data-dir data --epochs 5 --batch 64 --lr 0.01 \ -# --hidden 256 --save models/mnist.bin --limit 60000 -# app.exe --mode train --arch cnn --c1 8 --c2 16 (卷积 + 池化, 更抗形变) -# app.exe --mode use --data-dir data --load models/mnist.bin --show 10 -# --download 自动下载缺失数据; --file 指定本地已下载 .gz(可 1~2 次) -# --no-aug 关闭数据增强(默认开: 训练时随机平移 ±2px) -# 注: use 模式的架构/hidden/通道以模型文件头为准, 无需与命令行走一致 -# -# 模型: MLP = Linear(784->hidden) -> ReLU -> Linear(hidden->10) -# CNN = Conv(1->c1,3x3,pad1) -> ReLU -> MaxPool2 -> Conv(c1->c2,3x3,pad1) -# -> ReLU -> MaxPool2 -> Linear(49*c2->hidden) -> ReLU -> Linear(hidden->10) -# 权重形状同 PyTorch: Conv(out,in,k,k) / Linear(out,in), b(out) -# 计算: torch-lite 线性前向走 vipersimd.simd_dot4d, relu 走 simd_max4d -# ============================================================ -import t, c -from stdint import * -import stdlib -import string -import stdio -import sys -import memhub -import argparse -import requests -import torch -import w32.win32console as w32cmd -import lib.MnistData as MnistData -import lib.MnistNet as MnistNet -import lib.AppGui as AppGui - -define CODE_PAGE = 65001 # UTF-8 控制台 - -# 主内存池(CLI 与 GUI 共用) -define POOL_SIZE = 536870912 # 512 MB - - -# ============================================================ -# CLI -# ============================================================ -def run_cli(pool: memhub.MemBuddy*) -> int: - parser: argparse.ArgumentParser* = argparse.ArgumentParser( - "ViperMNIST", "28x28 MNIST 手写数字识别 (train/use)", pool=pool) - parser.add_argument("--mode", None, argparse.STRING, 0, "train", False, - argparse.STORE, "train=训练 / use=加载模型推理") - parser.add_argument("--data-dir", None, argparse.STRING, 0, "data", False, - argparse.STORE, "MNIST IDX 文件所在目录") - parser.add_argument("--epochs", None, argparse.INT, 5, None, False, - argparse.STORE, "训练轮数") - parser.add_argument("--batch", None, argparse.INT, 64, None, False, - argparse.STORE, "批大小") - parser.add_argument("--lr", None, argparse.STRING, 0, "0.01", False, - argparse.STORE, "学习率(小数; 训练用重球法, 默认 0.01)") - parser.add_argument("--hidden", None, argparse.INT, 256, None, False, - argparse.STORE, "隐藏层宽度(CNN 下为 FC1 宽度)") - parser.add_argument("--arch", None, argparse.STRING, 0, "mlp", False, - argparse.STORE, "架构: mlp=全连接 / cnn=卷积+池化") - parser.add_argument("--c1", None, argparse.INT, 8, None, False, - argparse.STORE, "CNN conv1 通道数(仅 --arch cnn 生效)") - parser.add_argument("--c2", None, argparse.INT, 16, None, False, - argparse.STORE, "CNN conv2 通道数(仅 --arch cnn 生效)") - parser.add_argument("--no-aug", None, argparse.BOOL, 0, None, False, - argparse.STORE_TRUE, "关闭数据增强(默认开启: 训练时随机平移 ±2px)") - parser.add_argument("--limit", None, argparse.INT, 0, None, False, - argparse.STORE, "样本上限(0=全部)") - parser.add_argument("--save", None, argparse.STRING, 0, "mnist.bin", - False, argparse.STORE, "训练保存路径") - parser.add_argument("--load", None, argparse.STRING, 0, "mnist.bin", - False, argparse.STORE, "推理加载路径") - parser.add_argument("--show", None, argparse.INT, 10, None, False, - argparse.STORE, "use 模式打印前 N 条预测") - parser.add_argument("--seed", None, argparse.INT, 42, None, False, - argparse.STORE, "随机种子") - parser.add_argument("--download", None, argparse.BOOL, 0, None, False, - argparse.STORE_TRUE, "自动下载缺失的 MNIST 数据") - parser.add_argument("--file", None, argparse.STRING, 0, None, False, - argparse.STORE, "本地已下载的 .gz(可 1~2 次: 图像/标签各一份), 优先本地解压替代联网") - parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False, - argparse.STORE_TRUE, "显示帮助并退出") - - args: argparse.ParsedArgs* = parser.parse_args(sys._argc, sys._argv) - if args is None: - stdio.printf("参数解析失败\n") - return 1 - if args.get_bool("help"): - parser.print_help() - return 0 - - mode: str = args.get_str("mode") - data_dir: str = args.get_str("data-dir") - epochs: int = args.get_int("epochs") - batch: int = args.get_int("batch") - hidden: int = args.get_int("hidden") - limit: int = args.get_int("limit") - show: int = args.get_int("show") - seed: int = args.get_int("seed") - save_path: str = args.get_str("save") - load_path: str = args.get_str("load") - arch_str: str = args.get_str("arch") - c1_arg: int = args.get_int("c1") - c2_arg: int = args.get_int("c2") - lr_str: str = args.get_str("lr") - download: int = 0 - if args.get_bool("download"): - download = 1 - no_aug: int = 0 - if args.get_bool("no-aug"): - no_aug = 1 - - # --file 本地 .gz(可 1~2 次): 按文件名含 -labels-/-images- 归类, 无名匹配按先后补空位 - loc_im: str = None - loc_lb: str = None - i_arg: int = 1 - while i_arg + 1 < sys._argc: - if string.strcmp(sys._argv[i_arg], "--file") == 0: - fv: str = sys._argv[i_arg + 1] - is_lb: int = 0 - if string.strstr(fv, "-labels-") is not None: - is_lb = 1 - is_im: int = 0 - if string.strstr(fv, "-images-") is not None: - is_im = 1 - if is_lb != 0 and is_im == 0 and loc_lb is None: - loc_lb = fv - elif is_im != 0 and is_lb == 0 and loc_im is None: - loc_im = fv - elif loc_im is None: - loc_im = fv - elif loc_lb is None: - loc_lb = fv - i_arg += 2 - else: - i_arg += 1 - file_set: int = 0 - if loc_im is not None or loc_lb is not None: - file_set = 1 - - lr: double = double(0.01) - if lr_str is not None and string.strlen(lr_str) > 0: - lr = MnistData.atof(lr_str, lr) - - MnistNet.rand_seed(uint64(seed)) - torch.manual_seed(int64(seed)) - - h: sizet = sizet(hidden) - # 架构与数据增强: 与 GUI 口径一致(通道数只在 CNN 下有意义) - arch: int = MnistNet.ARCH_MLP - if string.strcmp(arch_str, "cnn") == 0 or string.strcmp(arch_str, "CNN") == 0: - arch = MnistNet.ARCH_CNN - c1: sizet = 0 - c2: sizet = 0 - if arch == MnistNet.ARCH_CNN: - c1 = sizet(c1_arg) - c2 = sizet(c2_arg) - augment: int = 1 - if no_aug != 0: - augment = 0 - stdio.printf("ViperMNIST mode=%s data=%s limit=%d hidden=%d epochs=%d batch=%d lr=%.3f arch=%s\n", - mode, data_dir, limit, hidden, epochs, batch, lr, arch_str) - - p_img: str = stdlib.malloc(1024) - p_lbl: str = stdlib.malloc(1024) - - if string.strcmp(mode, "train") == 0: - net: MnistNet.Net* = MnistNet.Net(pool, h, sizet(arch), c1, c2) - if MnistNet.net_ok(net) == 0: - stdio.printf("FAIL: 网络分配失败\n") - return 1 - MnistNet.init_net_weights(net) - MnistData.idx_paths(data_dir, 0, p_img, p_lbl) - if download != 0 or file_set != 0: - if MnistData.ensure_mnist(data_dir, 0, download, loc_im, loc_lb) != 0: - stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n") - return 1 - cap: sizet = sizet(60000) - if limit > 0 and limit < 60000: - cap = sizet(limit) - xbuf: double* = stdlib.malloc(cap * MnistData.N_IN * 8) - ybuf: int* = stdlib.malloc(cap * 4) - if xbuf is None or ybuf is None: - stdio.printf("FAIL: 训练数据缓冲分配失败\n") - return 1 - n_im: sizet = MnistData.load_mnist_images(p_img, xbuf, cap) - n_lb: sizet = MnistData.load_mnist_labels(p_lbl, ybuf, cap) - n_tr: sizet = n_im - if n_lb < n_tr: - n_tr = n_lb - stdio.printf("加载训练样本=%zu 张 (%s)\n", n_tr, MnistNet.arch_name(arch)) - if n_tr == 0: - stdio.printf("未找到可用数据。如 data 目录文件残缺/损坏, 请加 --download 重新拉取或用 --file 指定本地 .gz\n") - return 1 - MnistNet.prog_init() - MnistNet.train_run(pool, net, xbuf, ybuf, n_tr, - sizet(batch), sizet(epochs), lr, save_path, augment) - stdlib.free(xbuf) - stdlib.free(ybuf) - elif string.strcmp(mode, "use") == 0: - # 架构/hidden/通道以模型文件头为准(命令行给的对推理无意义), 先读头再建网 - minfo: int* = stdlib.malloc(20) - if minfo is None: - stdio.printf("FAIL: 模型头缓冲分配失败\n") - return 1 - if MnistNet.peek_model(load_path, minfo) == 0: - stdlib.free(minfo) - stdio.printf("加载模型失败, 请先训练(--mode train): %s\n", load_path) - return 1 - f_arch: int = minfo[0] - f_hidden: int = minfo[1] - f_c1: int = minfo[2] - f_c2: int = minfo[3] - stdlib.free(minfo) - uh: sizet = sizet(f_hidden) - uc1: sizet = 0 - uc2: sizet = 0 - if f_arch == MnistNet.ARCH_CNN: - uc1 = sizet(f_c1) - uc2 = sizet(f_c2) - net2: MnistNet.Net* = MnistNet.Net(pool, uh, sizet(f_arch), - uc1, uc2) - if MnistNet.net_ok(net2) == 0: - stdio.printf("FAIL: 网络分配失败\n") - return 1 - MnistData.idx_paths(data_dir, 1, p_img, p_lbl) - if download != 0 or file_set != 0: - if MnistData.ensure_mnist(data_dir, 1, download, loc_im, loc_lb) != 0: - stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n") - return 1 - cap2: sizet = sizet(10000) - if limit > 0 and limit < 10000: - cap2 = sizet(limit) - xbuf2: double* = stdlib.malloc(cap2 * MnistData.N_IN * 8) - ybuf2: int* = stdlib.malloc(cap2 * 4) - if xbuf2 is None or ybuf2 is None: - stdio.printf("FAIL: 测试数据缓冲分配失败\n") - return 1 - n_te: sizet = MnistData.load_mnist_images(p_img, xbuf2, cap2) - n_tl: sizet = MnistData.load_mnist_labels(p_lbl, ybuf2, cap2) - if n_tl < n_te: - n_te = n_tl - stdio.printf("加载测试样本=%zu 张\n", n_te) - if n_te == 0: - return 1 - if MnistNet.load_model(net2, load_path) != 0: - stdio.printf("加载模型失败, 请先训练(--mode train)\n") - return 1 - stdio.printf("加载模型: %s (%s, hidden=%d)\n", - load_path, MnistNet.arch_name(f_arch), f_hidden) - MnistNet.evaluate_net(pool, net2, xbuf2, ybuf2, n_te, - sizet(batch), sizet(show)) - stdlib.free(xbuf2) - stdlib.free(ybuf2) - else: - stdio.printf("未知模式: %s (可选 train/use)\n", mode) - return 1 - - stdlib.free(p_img) - stdlib.free(p_lbl) - return 0 - - -# ============================================================ -# 入口 -# ============================================================ -def main() -> int: - # UTF-8 控制台(与 TransPyV main 一致) - w32cmd.SetConsoleOutputCP(CODE_PAGE) - w32cmd.SetConsoleCP(CODE_PAGE) - - # 主内存池: CLI 与 GUI 共用, 先建池再解析 argv(GUI 分支也需要池) - arena: bytes = stdlib.malloc(POOL_SIZE) - if arena is None: - stdio.printf("FAIL: 无法分配主池\n") - return 1 - mb: memhub.MemBuddy* = memhub.MemBuddy(arena, POOL_SIZE, 0) - if mb is None: - stdio.printf("FAIL: MemBuddy 初始化失败\n") - return 1 - argparse._mbuddy = mb - sys._mbuddy = mb - requests._mbuddy = mb # requests/https 内部用 _mbuddy 分配响应缓冲 - sys._init_argv() - - # 无参数 → Qt 面板; 有参数 → CLI - if sys._argc <= 1: - return AppGui.run(mb) - return run_cli(mb) +# -*- coding: utf-8 -*- +# ============================================================ +# ViperMNIST - 28x28 手写数字识别(MLP / CNN, torch-lite) +# +# 入口分发: +# * 无命令行参数 → 启动 Qt6 图形面板(数据/训练/推理, 含 3D 网络图) +# * 带命令行参数 → 走原 CLI(train / use) +# +# CLI 用法: +# app.exe --mode train --data-dir data --epochs 5 --batch 64 --lr 0.01 \ +# --hidden 256 --save models/mnist.bin --limit 60000 +# app.exe --mode train --arch cnn --c1 8 --c2 16 (卷积 + 池化, 更抗形变) +# app.exe --mode use --data-dir data --load models/mnist.bin --show 10 +# --download 自动下载缺失数据; --file 指定本地已下载 .gz(可 1~2 次) +# --no-aug 关闭数据增强(默认开: 训练时随机平移 ±2px) +# 注: use 模式的架构/hidden/通道以模型文件头为准, 无需与命令行走一致 +# +# 模型: MLP = Linear(784->hidden) -> ReLU -> Linear(hidden->10) +# CNN = Conv(1->c1,3x3,pad1) -> ReLU -> MaxPool2 -> Conv(c1->c2,3x3,pad1) +# -> ReLU -> MaxPool2 -> Linear(49*c2->hidden) -> ReLU -> Linear(hidden->10) +# 权重形状同 PyTorch: Conv(out,in,k,k) / Linear(out,in), b(out) +# 计算: torch-lite 线性前向走 vipersimd.simd_dot4d, relu 走 simd_max4d +# ============================================================ +import t, c +from stdint import * +import stdlib +import string +import stdio +import sys +import memhub +import argparse +import requests +import torch +import w32.win32console as w32cmd +import lib.MnistData as MnistData +import lib.MnistNet as MnistNet +import lib.AppGui as AppGui + +define CODE_PAGE = 65001 # UTF-8 控制台 + +# 主内存池(CLI 与 GUI 共用) +define POOL_SIZE = 536870912 # 512 MB + + +# ============================================================ +# CLI +# ============================================================ +def run_cli(pool: memhub.MemBuddy*) -> int: + parser: argparse.ArgumentParser* = argparse.ArgumentParser( + "ViperMNIST", "28x28 MNIST 手写数字识别 (train/use)", pool=pool) + parser.add_argument("--mode", None, argparse.STRING, 0, "train", False, + argparse.STORE, "train=训练 / use=加载模型推理") + parser.add_argument("--data-dir", None, argparse.STRING, 0, "data", False, + argparse.STORE, "MNIST IDX 文件所在目录") + parser.add_argument("--epochs", None, argparse.INT, 5, None, False, + argparse.STORE, "训练轮数") + parser.add_argument("--batch", None, argparse.INT, 64, None, False, + argparse.STORE, "批大小") + parser.add_argument("--lr", None, argparse.STRING, 0, "0.01", False, + argparse.STORE, "学习率(小数; 训练用重球法, 默认 0.01)") + parser.add_argument("--hidden", None, argparse.INT, 256, None, False, + argparse.STORE, "隐藏层宽度(CNN 下为 FC1 宽度)") + parser.add_argument("--arch", None, argparse.STRING, 0, "mlp", False, + argparse.STORE, "架构: mlp=全连接 / cnn=卷积+池化") + parser.add_argument("--c1", None, argparse.INT, 8, None, False, + argparse.STORE, "CNN conv1 通道数(仅 --arch cnn 生效)") + parser.add_argument("--c2", None, argparse.INT, 16, None, False, + argparse.STORE, "CNN conv2 通道数(仅 --arch cnn 生效)") + parser.add_argument("--no-aug", None, argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "关闭数据增强(默认开启: 训练时随机平移 ±2px)") + parser.add_argument("--limit", None, argparse.INT, 0, None, False, + argparse.STORE, "样本上限(0=全部)") + parser.add_argument("--save", None, argparse.STRING, 0, "mnist.bin", + False, argparse.STORE, "训练保存路径") + parser.add_argument("--load", None, argparse.STRING, 0, "mnist.bin", + False, argparse.STORE, "推理加载路径") + parser.add_argument("--show", None, argparse.INT, 10, None, False, + argparse.STORE, "use 模式打印前 N 条预测") + parser.add_argument("--seed", None, argparse.INT, 42, None, False, + argparse.STORE, "随机种子") + parser.add_argument("--download", None, argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "自动下载缺失的 MNIST 数据") + parser.add_argument("--file", None, argparse.STRING, 0, None, False, + argparse.STORE, "本地已下载的 .gz(可 1~2 次: 图像/标签各一份), 优先本地解压替代联网") + parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False, + argparse.STORE_TRUE, "显示帮助并退出") + + args: argparse.ParsedArgs* = parser.parse_args(sys._argc, sys._argv) + if args is None: + stdio.printf("参数解析失败\n") + return 1 + if args.get_bool("help"): + parser.print_help() + return 0 + + mode: str = args.get_str("mode") + data_dir: str = args.get_str("data-dir") + epochs: int = args.get_int("epochs") + batch: int = args.get_int("batch") + hidden: int = args.get_int("hidden") + limit: int = args.get_int("limit") + show: int = args.get_int("show") + seed: int = args.get_int("seed") + save_path: str = args.get_str("save") + load_path: str = args.get_str("load") + arch_str: str = args.get_str("arch") + c1_arg: int = args.get_int("c1") + c2_arg: int = args.get_int("c2") + lr_str: str = args.get_str("lr") + download: int = 0 + if args.get_bool("download"): + download = 1 + no_aug: int = 0 + if args.get_bool("no-aug"): + no_aug = 1 + + # --file 本地 .gz(可 1~2 次): 按文件名含 -labels-/-images- 归类, 无名匹配按先后补空位 + loc_im: str = None + loc_lb: str = None + i_arg: int = 1 + while i_arg + 1 < sys._argc: + if string.strcmp(sys._argv[i_arg], "--file") == 0: + fv: str = sys._argv[i_arg + 1] + is_lb: int = 0 + if string.strstr(fv, "-labels-") is not None: + is_lb = 1 + is_im: int = 0 + if string.strstr(fv, "-images-") is not None: + is_im = 1 + if is_lb != 0 and is_im == 0 and loc_lb is None: + loc_lb = fv + elif is_im != 0 and is_lb == 0 and loc_im is None: + loc_im = fv + elif loc_im is None: + loc_im = fv + elif loc_lb is None: + loc_lb = fv + i_arg += 2 + else: + i_arg += 1 + file_set: int = 0 + if loc_im is not None or loc_lb is not None: + file_set = 1 + + lr: double = double(0.01) + if lr_str is not None and string.strlen(lr_str) > 0: + lr = MnistData.atof(lr_str, lr) + + MnistNet.rand_seed(uint64(seed)) + torch.manual_seed(int64(seed)) + + h: sizet = sizet(hidden) + # 架构与数据增强: 与 GUI 口径一致(通道数只在 CNN 下有意义) + arch: int = MnistNet.ARCH_MLP + if string.strcmp(arch_str, "cnn") == 0 or string.strcmp(arch_str, "CNN") == 0: + arch = MnistNet.ARCH_CNN + c1: sizet = 0 + c2: sizet = 0 + if arch == MnistNet.ARCH_CNN: + c1 = sizet(c1_arg) + c2 = sizet(c2_arg) + augment: int = 1 + if no_aug != 0: + augment = 0 + stdio.printf("ViperMNIST mode=%s data=%s limit=%d hidden=%d epochs=%d batch=%d lr=%.3f arch=%s\n", + mode, data_dir, limit, hidden, epochs, batch, lr, arch_str) + + p_img: str = stdlib.malloc(1024) + p_lbl: str = stdlib.malloc(1024) + + if string.strcmp(mode, "train") == 0: + net: MnistNet.Net* = MnistNet.Net(pool, h, sizet(arch), c1, c2) + if MnistNet.net_ok(net) == 0: + stdio.printf("FAIL: 网络分配失败\n") + return 1 + MnistNet.init_net_weights(net) + MnistData.idx_paths(data_dir, 0, p_img, p_lbl) + if download != 0 or file_set != 0: + if MnistData.ensure_mnist(data_dir, 0, download, loc_im, loc_lb) != 0: + stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n") + return 1 + cap: sizet = sizet(60000) + if limit > 0 and limit < 60000: + cap = sizet(limit) + xbuf: double* = stdlib.malloc(cap * MnistData.N_IN * 8) + ybuf: int* = stdlib.malloc(cap * 4) + if xbuf is None or ybuf is None: + stdio.printf("FAIL: 训练数据缓冲分配失败\n") + return 1 + n_im: sizet = MnistData.load_mnist_images(p_img, xbuf, cap) + n_lb: sizet = MnistData.load_mnist_labels(p_lbl, ybuf, cap) + n_tr: sizet = n_im + if n_lb < n_tr: + n_tr = n_lb + stdio.printf("加载训练样本=%zu 张 (%s)\n", n_tr, MnistNet.arch_name(arch)) + if n_tr == 0: + stdio.printf("未找到可用数据。如 data 目录文件残缺/损坏, 请加 --download 重新拉取或用 --file 指定本地 .gz\n") + return 1 + MnistNet.prog_init() + MnistNet.train_run(pool, net, xbuf, ybuf, n_tr, + sizet(batch), sizet(epochs), lr, save_path, augment) + stdlib.free(xbuf) + stdlib.free(ybuf) + elif string.strcmp(mode, "use") == 0: + # 架构/hidden/通道以模型文件头为准(命令行给的对推理无意义), 先读头再建网 + minfo: int* = stdlib.malloc(20) + if minfo is None: + stdio.printf("FAIL: 模型头缓冲分配失败\n") + return 1 + if MnistNet.peek_model(load_path, minfo) == 0: + stdlib.free(minfo) + stdio.printf("加载模型失败, 请先训练(--mode train): %s\n", load_path) + return 1 + f_arch: int = minfo[0] + f_hidden: int = minfo[1] + f_c1: int = minfo[2] + f_c2: int = minfo[3] + stdlib.free(minfo) + uh: sizet = sizet(f_hidden) + uc1: sizet = 0 + uc2: sizet = 0 + if f_arch == MnistNet.ARCH_CNN: + uc1 = sizet(f_c1) + uc2 = sizet(f_c2) + net2: MnistNet.Net* = MnistNet.Net(pool, uh, sizet(f_arch), + uc1, uc2) + if MnistNet.net_ok(net2) == 0: + stdio.printf("FAIL: 网络分配失败\n") + return 1 + MnistData.idx_paths(data_dir, 1, p_img, p_lbl) + if download != 0 or file_set != 0: + if MnistData.ensure_mnist(data_dir, 1, download, loc_im, loc_lb) != 0: + stdio.printf("数据就绪失败, 请检查 --file 路径 / 网络 / data-dir\n") + return 1 + cap2: sizet = sizet(10000) + if limit > 0 and limit < 10000: + cap2 = sizet(limit) + xbuf2: double* = stdlib.malloc(cap2 * MnistData.N_IN * 8) + ybuf2: int* = stdlib.malloc(cap2 * 4) + if xbuf2 is None or ybuf2 is None: + stdio.printf("FAIL: 测试数据缓冲分配失败\n") + return 1 + n_te: sizet = MnistData.load_mnist_images(p_img, xbuf2, cap2) + n_tl: sizet = MnistData.load_mnist_labels(p_lbl, ybuf2, cap2) + if n_tl < n_te: + n_te = n_tl + stdio.printf("加载测试样本=%zu 张\n", n_te) + if n_te == 0: + return 1 + if MnistNet.load_model(net2, load_path) != 0: + stdio.printf("加载模型失败, 请先训练(--mode train)\n") + return 1 + stdio.printf("加载模型: %s (%s, hidden=%d)\n", + load_path, MnistNet.arch_name(f_arch), f_hidden) + MnistNet.evaluate_net(pool, net2, xbuf2, ybuf2, n_te, + sizet(batch), sizet(show)) + stdlib.free(xbuf2) + stdlib.free(ybuf2) + else: + stdio.printf("未知模式: %s (可选 train/use)\n", mode) + return 1 + + stdlib.free(p_img) + stdlib.free(p_lbl) + return 0 + + +# ============================================================ +# 入口 +# ============================================================ +def main() -> int: + # UTF-8 控制台(与 ViperC main 一致) + w32cmd.SetConsoleOutputCP(CODE_PAGE) + w32cmd.SetConsoleCP(CODE_PAGE) + + # 主内存池: CLI 与 GUI 共用, 先建池再解析 argv(GUI 分支也需要池) + arena: bytes = stdlib.malloc(POOL_SIZE) + if arena is None: + stdio.printf("FAIL: 无法分配主池\n") + return 1 + mb: memhub.MemBuddy* = memhub.MemBuddy(arena, POOL_SIZE, 0) + if mb is None: + stdio.printf("FAIL: MemBuddy 初始化失败\n") + return 1 + argparse._mbuddy = mb + sys._mbuddy = mb + requests._mbuddy = mb # requests/https 内部用 _mbuddy 分配响应缓冲 + sys._init_argv() + + # 无参数 → Qt 面板; 有参数 → CLI + if sys._argc <= 1: + return AppGui.run(mb) + return run_cli(mb) diff --git a/ViperMNIST/project.vpj b/ViperMNIST/project.vpj index e45f049..0935c65 100644 --- a/ViperMNIST/project.vpj +++ b/ViperMNIST/project.vpj @@ -3,7 +3,7 @@ "version": "2.0.0", "description": "MNIST 手写数字识别(28x28 灰度, 两层 MLP): 无参数启动 vqt6 Qt 面板(数据/训练/推理 + 3D 网络图 + Qt Charts 曲线), 带参数走原 CLI(train/use); 计算走 includes/torch (仿 PyTorch 迷你库, 线性层内积 vipersimd dot4/relu max4d)", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperOpenSSLProject/project.vpj b/ViperOpenSSLProject/project.vpj index 6a1613b..cb0ffc4 100644 --- a/ViperOpenSSLProject/project.vpj +++ b/ViperOpenSSLProject/project.vpj @@ -2,7 +2,7 @@ "name": "ViperOpenSSLProject - OpenSSL 3.x FFI Test", "version": "1.0.0", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperQtHelloWorld/project.vpj b/ViperQtHelloWorld/project.vpj index 3f282f6..577a6bf 100644 --- a/ViperQtHelloWorld/project.vpj +++ b/ViperQtHelloWorld/project.vpj @@ -3,7 +3,7 @@ "version": "0.1.0", "description": "vqt6 第一个示例 - 创建一个 Qt6 窗口,点击按钮退出", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": ["-filetype=obj", "-relocation-model=pic"] diff --git a/ViperQtProject/App/main.vp b/ViperQtProject/App/main.vp index 34d23ae..47f0cce 100644 --- a/ViperQtProject/App/main.vp +++ b/ViperQtProject/App/main.vp @@ -676,7 +676,7 @@ def main() -> int: leaf.setChecked(1) leaf.setSize(1200) g1.addChild(leaf) - leaf = vqt6.QTreeWidgetItem("网络与调试工具(QtNetwork + TPV)[220 MB]") + leaf = vqt6.QTreeWidgetItem("网络与调试工具(QtNetwork + VPC)[220 MB]") leaf.setCheckable(1) leaf.setChecked(0) leaf.setSize(220) diff --git a/ViperQtProject/project.vpj b/ViperQtProject/project.vpj index f07ee1c..dd654a1 100644 --- a/ViperQtProject/project.vpj +++ b/ViperQtProject/project.vpj @@ -2,7 +2,7 @@ "name": "ViperQtProject - Qt6 GUI Test", "version": "1.0.0", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperRequestsTest/project.vpj b/ViperRequestsTest/project.vpj index af3dd73..b9634d6 100644 --- a/ViperRequestsTest/project.vpj +++ b/ViperRequestsTest/project.vpj @@ -2,7 +2,7 @@ "name": "ViperRequestsTest - HTTP(S) Client Test", "version": "1.0.0", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperSpeedBenchmark/README.md b/ViperSpeedBenchmark/README.md index df41e79..77fb42b 100644 --- a/ViperSpeedBenchmark/README.md +++ b/ViperSpeedBenchmark/README.md @@ -108,7 +108,7 @@ out[i] = a[i] * b[i] + c[i] # 元素独立, 单趟融合乘加; 每元素 | 文件 | 说明 | | --- | --- | -| `project.vpj` | Viper 工程配置(产物 `.tpv_build/output/app.exe`) | +| `project.vpj` | Viper 工程配置(产物 `__vpcbuild__/output/app.exe`) | | `App/main.vp` | Viper 实现: 8 个内核(FMA/ADD/MUL/SQRT × SIMD/原生) + 线程绑定 + QPC/周期双计时 + 进程内多 run; 自解析命令行 `[runs] [len] [iters] [mode]`(GetCommandLineA, 不依赖 sys/memhub) | | `bench_c.c` | 手写 C: 裸数组 + **全指针 `__restrict`**(fill/内核/校验和/local 指针都加) + noinline, `-O2 -mavx2 -mfma -ffp-contract=fast` 自动向量化单趟 FMA | | `bench_cpp.cpp` | 手写 C++: `std::vector` + `__restrict`, 同口径(`-O2 -mavx2 -mfma -ffp-contract=fast`) | @@ -131,7 +131,7 @@ out[i] = a[i] * b[i] + c[i] # 元素独立, 单趟融合乘加; 每元素 ### 5.1 构建 Viper 部分(一次性) 在本工程目录(`ViperSpeedBenchmark/`)用你惯用的 tpv 方式构建 `project.vpj`, -产物应为 `.tpv_build/output/app.exe`。若未构建, `run_bench.py` 会提示并**跳过 +产物应为 `__vpcbuild__/output/app.exe`。若未构建, `run_bench.py` 会提示并**跳过 全部 Viper 内核变体** 继续其它实现。 > **改了 `App/main.vp` 或 `includes/vipersimd.vp` 后必须重建**, 否则任一 Viper diff --git a/ViperSpeedBenchmark/project.vpj b/ViperSpeedBenchmark/project.vpj index 6bd99cb..a5aedd9 100644 --- a/ViperSpeedBenchmark/project.vpj +++ b/ViperSpeedBenchmark/project.vpj @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "同内核多实现测速基准: out[i]=a[i]*b[i]+c[i] (len=16384, iters=65536, 每次run≈2.147e9 flops; 工作集512KiB 常驻私有L2)。Viper 侧第4个命令行参数 mode 可切 8 个内核: FMA/ADD/MUL/SQRT 各一对 SIMD(simd_*_array) 与 原生(scalar_*_array), 用于 SIMD 加速比对照; mode=0 的 FMA SIMD 与 C/C++/Python 对齐", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperSpeedBenchmark/run_bench.py b/ViperSpeedBenchmark/run_bench.py index 344ea71..264f3a2 100644 --- a/ViperSpeedBenchmark/run_bench.py +++ b/ViperSpeedBenchmark/run_bench.py @@ -188,7 +188,7 @@ NATIVE_FLAGS = ["-O2", "-mavx2", "-mfma", "-ffp-contract=fast"] # Viper 内核实现名 -> (传给 app.exe 的第 4 个参数 mode, 显示名)。 -# 全部共用同一个 .tpv_build/output/app.exe, 只差这一个 mode 参数 —— 除"跑哪份内核" +# 全部共用同一个 __vpcbuild__/output/app.exe, 只差这一个 mode 参数 —— 除"跑哪份内核" # 外没有任何差异, 这是 SIMD vs 原生 对照可信的前提(见 App/main.vp 的 KERNEL_* 常量)。 # 命名规则: `` = SIMD, `scalar_` = 同操作的标量(原生)对照。 VIPER_KERNELS = [ @@ -257,7 +257,7 @@ def iters_for(size): def viper_exe(root): - return root / ".tpv_build" / "output" / "app.exe" + return root / "__vpcbuild__" / "output" / "app.exe" # ------------------------------------------------------------ @@ -431,7 +431,7 @@ def build_arg_parser(): p.add_argument("--py-mode", default=None, choices=["auto", "numpy", "pure"], help="覆盖 bench_py.py 的运行模式(auto/numpy/pure)") p.add_argument("--viper-exe", default=None, - help="覆盖 Viper 产物路径(默认 .tpv_build/output/app.exe)") + help="覆盖 Viper 产物路径(默认 __vpcbuild__/output/app.exe)") p.add_argument("--flops-check", action="store_true", help="核对 RESULT 行的 flops 字段是否与 CFG 总运算量一致, " "并报告 flops≈2e9(时长≈1s)的行占比及降规模提示") @@ -536,7 +536,7 @@ def main(argv=None): + ", ".join(f"{n}(mode={VIPER_MODE[n]})" for n in viper_wanted)) else: emit(f"[viper] 未找到 Viper 产物: {vpy_exe}") - emit(" 请先在本工程目录用 tpv 构建 project.vpj(生成 .tpv_build/output/app.exe),") + emit(" 请先在本工程目录用 tpv 构建 project.vpj(生成 __vpcbuild__/output/app.exe),") emit(" 本次将跳过全部 Viper 内核变体。") # ---- 逐尺寸 × 逐实现跑测(每组=一次进程启动) ---- @@ -804,7 +804,7 @@ def main(argv=None): f" | [{lab_other}] {other_us:>11.3f} us {gfl(other_us):>8.3f} GFLOPS" f" | {aff_txt} | {'PASS' if st['passed'] else 'FAIL'}") if not any(im == "viper" for (_, im) in results): - emit(" (viper 已跳过: 请先构建 .tpv_build/output/app.exe)") + emit(" (viper 已跳过: 请先构建 __vpcbuild__/output/app.exe)") for impl, note in compile_notes: emit(f" ({impl} 已跳过: 编译失败, 见上方)") emit("=" * 78) diff --git a/ViperTestProject/project.vpj b/ViperTestProject/project.vpj index 3c87f73..d109529 100644 --- a/ViperTestProject/project.vpj +++ b/ViperTestProject/project.vpj @@ -2,7 +2,7 @@ "name": "Standard Template Project", "version": "1.0.0", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [ diff --git a/ViperZipfileProject/project.vpj b/ViperZipfileProject/project.vpj index 7f0c81f..069c817 100644 --- a/ViperZipfileProject/project.vpj +++ b/ViperZipfileProject/project.vpj @@ -2,7 +2,7 @@ "name": "ViperZipfileProject - zipfile 模块测试", "version": "1.0.0", "source_dir": "./App", - "build_dir": "./.tpv_build", + "build_dir": "./__vpcbuild__", "compiler": { "cmd": "llc", "flags": [