news 2026/9/19 13:01:12

CANN Runtime msproftx 扩展接口完全指南:Stamp 事件标记、范围打点与 Tensor 信息上报实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN Runtime msproftx 扩展接口完全指南:Stamp 事件标记、范围打点与 Tensor 信息上报实战

CANN Runtime msproftx 扩展接口完全指南:Stamp 事件标记、范围打点与 Tensor 信息上报实战

【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime

导读

本文基于 CANN 开源运行时仓库(cann/runtime)中的 msproftx 扩展接口文档,系统讲解 msproftx 扩展接口的完整使用方式。msproftx 是 CANN Profiling 体系中面向用户的自定义打点能力,用于在采集任务中标注瞬时事件(Stamp)、时间范围(Push/Pop、Range)以及调用栈信息,最终在 Profiling 解析导出的msprof_tx summary数据中呈现。读完本文,你将掌握 11 个 msproftx 扩展接口的调用约束与配对关系、如何在aclprofStart/aclprofStop之间组织打点流程、如何在多线程场景下用 Range 接口代替线程栈接口,以及如何在 Torch 场景下上报 Tensor 信息,并深入理解其底层实现原理。


一、msproftx 扩展接口概述

msproftx(MS-Prof TX,即 Profiling 自定义打点扩展)是 CANN Runtime Profiling 能力中面向用户的扩展打点接口集。与 19-01 数据采集接口中的aclprofStart/aclprofStop等粗粒度采集控制接口不同,msproftx 允许用户在自己的业务代码中插入细粒度的性能标记,从而把"业务语义"(例如模型加载、前向传播、算子下发、预处理等阶段)映射到采集到的性能数据上。

从源码声明看,这些接口定义在 include/external/acl/acl_prof.h 中(MSVP_PROF_API导出),底层实现由 src/dfx/msprof/collector/dvvp/profimpl/adapter/src/msproftx_adaptor.cpp 中的ProfAcl*系列函数转发给 msprof_tx_manager.cpp 中的MsprofTxManager单例完成。调用 msproftx 相关接口的前提是:在aclprofCreateConfig创建配置时使能采集类型ACL_PROF_MSPROFTX(其值为0x0080ULL,定义见 acl_prof.h)。

1.1 接口全景一览

按功能可以把 11 个扩展接口划分为五类:

分类接口功能定位
标记对象管理aclprofCreateStamp/aclprofDestroyStamp创建 / 释放 msproftx 事件标记(Stamp)对象
标记描述aclprofSetStampTraceMessage为 Stamp 携带字符串描述,展示在msprof_tx summary
瞬时事件标记aclprofMark/aclprofMarkEx记录瞬时事件(Mark),后者可下打到指定 Stream
时间跨度标记aclprofPush/aclprofPopaclprofRangeStart/aclprofRangeStop记录一段时间的开始与结束,前者线程内嵌套,后者可跨线程
Tensor 信息上报aclprofRangePushEx/aclprofRangePop在 Torch 场景下上报 Tensor 信息
工具函数aclprofStr2Id将字符串(如算子名)转换为哈希 ID

1.2 使用前提与整体调用约束

  • 调用时机:msproftx 相关接口必须在 aclprofStart 与 aclprofStop 之间调用,且aclprofStart的 aclprofConfig 数据需与aclprofStop保持一致,采集类型需包含ACL_PROF_MSPROFTX
  • 配对使用aclprofCreateStamp/aclprofDestroyStampaclprofPush/aclprofPopaclprofRangeStart/aclprofRangeStopaclprofRangePushEx/aclprofRangePop均为成对接口。
  • 推荐调用顺序aclprofStartaclprofCreateStampaclprofSetStampTraceMessageaclprofMark→(aclprofPush/aclprofPop)或(aclprofRangeStart/aclprofRangeStop)→aclprofDestroyStampaclprofStop

二、标记对象生命周期管理:aclprofCreateStamp 与 aclprofDestroyStamp

2.1 aclprofCreateStamp:创建事件标记

void *aclprofCreateStamp()

功能说明:创建 msproftx 事件标记对象。后续调用aclprofMarkaclprofSetStampTraceMessageaclprofPushaclprofRangeStart时,都需要把该指针作为入参传入,用于标识记录的是同一个事件的时间跨度。

返回值

  • 返回void*指针:成功;
  • 返回nullptr:失败(例如未先调用aclprofStart)。

约束:必须与aclprofDestroyStamp配对使用,且需在aclprofStart之后调用。

源码佐证:在 msprof_tx_manager.cpp 的CreateStamp()实现中,会先检查MsprofTxManager是否已初始化(即是否已通过aclprofStart触发MsprofTxInit),未初始化时记录EK0002错误并返回nullptr;初始化后从内存池stampPool_->CreateStamp()取出 Stamp。也就是说,Stamp 并非普通堆对象,而是从预分配的内存池(CURRENT_STAMP_SIZE指定池容量)中分配,这有利于高频打点场景下的内存稳定性。

2.2 aclprofSetStampTraceMessage:为标记携带描述信息

aclError aclprofSetStampTraceMessage(void *stamp, const char *msg, uint32_t msgLen)

功能说明:为 msproftx 事件标记携带字符串描述。该描述会出现在 Profiling 解析并导出的结果中的msprof_tx summary数据里,便于在分析工具中快速识别打点含义(例如 "model_load_mark"、"forward_pass_push")。

参数说明

参数名输入/输出说明
stamp输入Stamp 指针,指代 msproftx 事件标记,即aclprofCreateStamp的返回值
msg输入Stamp 信息字符串指针
msgLen输入字符串长度

返回值:返回0表示成功,返回其他值表示失败,参见 aclError。

约束:需在aclprofCreateStampaclprofDestroyStamp之间调用。

源码佐证:底层 SetStampTraceMessage 实现中定义了MAX_MSG_LEN = 128,若msgLen >= 128会报错并返回失败;合法的消息通过strncpy_s拷入 Stamp 内部的message字段并补\0。因此建议描述字符串长度控制在 127 字节以内

2.3 aclprofDestroyStamp:释放事件标记

void aclprofDestroyStamp(void *stamp)

功能说明:释放 msproftx 事件标记对象,将 Stamp 归还内存池(而非直接free)。实现见 DestroyStamp,对nullptr入参会记录EK0006参数错误。

参数说明

参数名输入/输出说明
stamp输入Stamp 指针,即aclprofCreateStamp的返回值

返回值:无。

约束:与aclprofCreateStamp配对使用,且应在aclprofStop之前调用。


三、瞬时事件标记:aclprofMark 与 aclprofMarkEx

3.1 aclprofMark:标记瞬时事件

aclError aclprofMark(void *stamp)

功能说明:标记一个瞬时事件(如"模型加载完成"、"执行结束")。调用后,Profiling 自动在 Stamp 中写入当前时间戳,并将Event type设置为Mark,表示完成一次 msproftx 采集打点。

参数说明

参数名输入/输出说明
stamp输入Stamp 指针,即aclprofCreateStamp的返回值

返回值:返回0表示成功,其他值表示失败,参见 aclError。

约束:在aclprofCreateStampaclprofDestroyStamp之间调用。

源码佐证:Mark() 实现中,startTimeendTime均取当前系统周期计数值(PlatformSysCycleTime()),eventType置为EventType::MARK,随后通过ReportStampData上报。

3.2 aclprofMarkEx:带 Stream 的瞬时打点

aclError aclprofMarkEx(const char *msg, size_t msgLen, aclrtStream stream)

功能说明:向指定的 Stream 流上下发打点任务,用于标识 Host 侧打点与 Device 侧打点任务之间的对应关系。与aclprofMark相比,aclprofMarkEx不依赖 Stamp 对象,而是直接把消息字符串与 Stream 关联起来。

参数说明

参数名输入/输出说明
msg输入打点信息字符串指针
msgLen输入字符串长度,最大支持 127 字符
stream输入指定 Stream,类型定义参见 aclrtStream

返回值:返回0表示成功,其他值表示失败,参见 aclError。

约束:无。

源码佐证:实现分两步完成(见 MarkEx / MarkExPoint):

  1. 先校验msgstream非空且strlen(msg) == msgLen、消息长度在1 ~ MAX_MESSAGE_LEN-1范围内;
  2. 调用注册的 Runtime 回调rtProfilerTraceExFunc_(即rtProfilerTraceEx),携带markIdMARKEX_MODEL_ID = 0xFFFFFFFFMARKEX_TAG_ID = 11以及 Stream 指针,把打点任务下发到 Device 侧;
  3. 将消息拷贝进MsprofTxInfo后通过 reporter 上报。

此外,源码中定义了MARKEX_MAX_CYCLE = 1000MARKEX_RANGE_TAG_ID = 12(Range 型打点使用的 tag),从源码结构可以推断其用于控制 MarkEx 相关任务索引的循环复用,以及区分瞬时/范围两类 Device 打点任务。


四、时间跨度标记:Push/Pop 与 RangeStart/RangeStop

时间跨度标记用于度量一段代码的执行耗时,msproftx 提供了两套语义等价、但使用场景不同的接口。

4.1 aclprofPush 与 aclprofPop:线程内嵌套范围

aclError aclprofPush(void *stamp) aclError aclprofPop()

功能说明aclprofPush记录时间跨度开始时间,aclprofPop记录结束时间。调用aclprofPush后,Profiling 自动在 Stamp 中记录开始时间戳,并将Event type设置为Push/PopaclprofPop记录结束时间戳。

参数说明aclprofPush):

参数名输入/输出说明
stamp输入Stamp 指针,即aclprofCreateStamp的返回值

返回值:均为返回0成功,其他值失败,参见 aclError。

约束

  • aclprofPop成对使用,表示时间跨度的开始与结束;
  • aclprofCreateStampaclprofDestroyStamp之间调用;
  • 不能跨线程调用。若需要跨线程,请使用aclprofRangeStart/aclprofRangeStop

源码佐证Push记录startTime后把 Stamp 压入 Stamp 池的线程栈(stampPool_->MsprofStampPush(stamp));Pop从栈中弹出 Stamp(弹栈失败会报EK0002,提示检查aclprofPush/aclprofPop配对),写入endTime并将eventType置为PUSH_OR_POP后上报。由于是"栈"语义,Push/Pop 天然支持嵌套,即先 Push A 再 Push B、然后依次 Pop B、Pop A,可形成嵌套范围。

4.2 aclprofRangeStart 与 aclprofRangeStop:可跨线程的范围标记

aclError aclprofRangeStart(void *stamp, uint32_t *rangeId) aclError aclprofRangeStop(uint32_t rangeId)

功能说明aclprofRangeStart记录时间跨度开始,aclprofRangeStop记录结束。调用aclprofRangeStart后,Profiling 自动在 Stamp 中记录开始时间戳,将Event type设置为Start/Stop,生成一个进程唯一的 id,并把 Stamp 保存在以进程粒度维护的一个 map中。aclprofRangeStop通过该唯一 id 找到对应的 Stamp 并记录结束时间戳。

参数说明

接口参数名输入/输出说明
aclprofRangeStartstamp输入Stamp 指针,即aclprofCreateStamp的返回值
aclprofRangeStartrangeId输出msproftx 事件标记的唯一标识,用于跨线程时区分
aclprofRangeStoprangeId输入msproftx 事件标记的唯一标识

返回值:均为返回0成功,其他值失败,参见 aclError。

约束

  • aclprofRangeStop成对使用;
  • aclprofCreateStampaclprofDestroyStamp之间调用;
  • 可以跨线程调用(这是与 Push/Pop 最核心的区别)。

源码佐证RangeStart(见 RangeStart)通过stampPool_->GetIdByStamp(stamp)生成唯一rangeId,并置stamp->isEnable = 1RangeStop通过stampPool_->GetStampById(rangeId)反查 Stamp,若查不到(例如传入了未由aclprofRangeStart返回的 id)会报EK0001参数错误。rangeId之所以能跨线程,正是因为它的保存粒度是进程级 map,而非线程栈。

4.3 Push/Pop 与 Range 的选择建议

维度aclprofPush / aclprofPopaclprofRangeStart / aclprofRangeStop
嵌套支持支持(栈语义)不支持嵌套,仅区间对
跨线程不支持支持
结束定位无参数,自动弹栈通过 rangeId 精确定位
典型场景单线程内嵌套调用链异步任务、多线程流水线

选型原则:如果打点发生在同一线程且存在嵌套调用结构(如外层"前向传播"包内层"算子分发"),优先用 Push/Pop;如果开始与结束发生在不同线程(如生产者-消费者、异步回调),必须改用 RangeStart/RangeStop。


五、Torch 场景 Tensor 信息上报:aclprofRangePushEx / aclprofRangePop 与 aclprofStr2Id

5.1 功能定位

aclrt<<<>>>(kernel 启动)场景下,用户可在算子加载接口前先调用aclprofRangePushEx上报 Tensor 信息,之后再调用aclprofRangePop,完成 Profiling 数据的上报。调用aclprofRangePushEx后,Profiling 判断messageTypeMESSAGE_TYPE_TENSOR_INFO时,会缓存 Tensor 信息;调用aclprofRangePop时再将缓存的 Tensor 信息上报。

5.2 aclprofRangePushEx

aclError aclprofRangePushEx(aclprofEventAttributes *attr)

参数说明

参数名输入/输出说明
attr输入需要上报的 Tensor 信息,结构体详见 aclprofEventAttributes

返回值:返回0成功,其他值失败,参见 aclError。

约束:与aclprofRangePop配对使用,先aclprofRangePushExaclprofRangePop

5.3 aclprofRangePop

aclError aclprofRangePop()

功能说明:上报缓存的 Tensor 信息(即aclprofRangePushEx缓存的那份数据)。

返回值:返回0成功,其他值失败,参见 aclError。

约束:与aclprofRangePushEx配对使用。

5.4 aclprofStr2Id:字符串转哈希 ID

uint64_t aclprofStr2Id(const char *message)

功能说明:msproftx 用于将字符串(例如算子名)转化为哈希 ID。在构造 Tensor 信息上报时,用哈希 ID 代替冗长的字符串,可以显著降低打点数据的体积。

参数说明

参数名输入/输出说明
message输入字符信息,例如算子名

返回值:返回哈希 ID;如果返回uint64_t类型的最大值则说明失败,其他值表示成功。

约束:与aclprofRangePushExaclprofRangePop配合使用,在aclprofRangePushEx之前调用。

5.5 数据结构:aclprofEventAttributes 与相关结构体

在 acl_prof.h 中定义了与 Tensor 信息上报配套的公共结构体,其布局已冻结以保持二进制兼容(新字段只能追加在尾部并提升ACL_PROF_EVENT_ATTR_VERSION):

#define ACL_PROF_EVENT_ATTR_VERSION 1 #define ACL_PROF_TENSOR_DATA_SHAPE_LEN 8 // shape 维度上限 typedef struct aclprofTensor { uint32_t type; // tensor类型, 0: input, 1: output uint32_t format; // format类型: aclFormat uint32_t dataType; // dataType类型 aclDataType uint32_t shapeDim; // shape dim <= 8 uint32_t shape[ACL_PROF_TENSOR_DATA_SHAPE_LEN]; // tensor内存大小 } aclprofTensor; typedef struct aclprofTensorInfo { uint64_t opNameId; // 通过 uint64_t aclprofStr2Id(const char *message) 得到 uint64_t opTypeId; uint32_t resv; uint32_t tensorNum; uint32_t kernelType; uint32_t blockNums; void* stream; // stream信息 aclprofTensor* tensors; } aclprofTensorInfo; typedef struct aclprofEventAttributes { uint16_t version; uint16_t size; uint32_t messageType; // MESSAGE_TYPE_TENSOR_INFO union Message { aclprofTensorInfo* tensorInfo; } message; } aclprofEventAttributes;

关键说明:

  • aclprofEventAttributes.messageType只有枚举ACL_PROF_MESSAGE_TYPE_TENSOR_INFO(值0)一个取值;
  • aclprofTensor.shape的维度上限为 8(ACL_PROF_TENSOR_DATA_SHAPE_LEN),shapeDim不得大于 8;
  • 头文件允许通过定义ACL_PROF_TENSOR_INFO_DEFINED来屏蔽官方结构定义、使用用户自定义结构,但前提是保持与上述冻结布局的二进制兼容;
  • 从源码结构可以推断:aclprofStr2Id得到的opNameId/opTypeId与字符串的对应关系会在 Profiling 解析阶段还原,从而在msprof_tx summary中展示可读的算子名。

六、源码级实现链路与关键细节

6.1 调用链总览

从仓库源码可以梳理出 msproftx 的完整调用链:

应用代码 → aclprofCreateStamp / aclprofMark / aclprofPush ... (include/external/acl/acl_prof.h 声明) → ProfAclCreateStamp / ProfAclMark / ProfAclPush ... (src/dfx/msprof/collector/dvvp/profimpl/adapter/src/msproftx_adaptor.cpp) → MsprofTxManager::CreateStamp / Mark / Push ... (src/dfx/msprof/collector/dvvp/msprof/msproftx/src/msprof_tx_manager.cpp) → stampPool_(Stamp 内存池)+ reporter_(数据上报)

6.2 关键实现要点

  1. 初始化与生命周期MsprofTxManager::Init()会创建ProfStampPool并初始化(容量为CURRENT_STAMP_SIZE字节),初始化失败会上报EK0201环境错误;UnInit()会依次反初始化 stampPool 与 reporter。manager 的初始化由aclprofStart流程触发(MsprofTxInit回调),因此文档要求"必须在aclprofStart/aclprofStop之间调用"是有实现依据的。

  2. 错误处理:所有入参校验失败都会通过MSPROF_INPUT_ERROR上报EK0006(参数为空)、EK0001(参数非法)或EK0002(接口顺序错误)等错误码,返回对应的ACL_ERROR_INVALID_PARAM等 aclError。这些错误码在 docs/zh/error_code_ref 中有对应说明。

  3. 线程信息采集:每次上报(ReportStampData)都会用OsalGetTid()记录当前线程 ID,MarkEx还会用OsalGetPid()记录进程 ID——这是跨线程 Range 语义能够在解析端正确归位的关键。

  4. Device 侧打点aclprofMarkEx与 Range 型 Device 打点通过rtProfilerTraceEx运行时接口把任务下发到 Stream,tagId区分瞬时(11)与范围(12)两种打点任务,modelId固定为0xFFFFFFFF

6.3 产品支持情况

根据接口文档,msproftx 扩展接口在以下产品上支持,在IPV350 上不支持

  • Ascend 950PR / Ascend 950DT:支持
  • Atlas A3 训练系列产品 / Atlas A3 推理系列产品:支持
  • Atlas A2 训练系列产品 / Atlas A2 推理系列产品:支持
  • Atlas 200I/500 A2 推理产品:支持
  • Atlas 推理系列产品:支持
  • Atlas 训练系列产品:支持
  • IPV350:不支持

另外,从 msproftx_adaptor.cpp 可以看到,所有接口在helper host 侧会直接拒绝执行并记录EK0004(接口不支持)错误,即 msproftx 打点只能运行在业务侧进程。


七、完整实战示例

仓库在 example/5_performance/profiling/1_msproftx 提供了可直接编译运行的 msproftx 样例(main.cpp+run.sh)。该样例除演示瞬时事件aclprofMark外,还演示了aclprofPush/aclprofPop嵌套范围标记aclprofRangeStart/aclprofRangeStop非嵌套范围标记,便于对照 NVTX 的常见使用模式。

7.1 样例核心流程

#include "acl/acl.h" #include "acl/acl_prof.h" // 创建带描述信息的 Stamp void* stamp = aclprofCreateStamp(); aclprofSetStampTraceMessage(stamp, "forward_pass_push", strlen("forward_pass_push")); // ... 初始化 Runtime 与 Profiling ... aclprofConfig* config = aclprofCreateConfig( deviceIdList, 1, ACL_AICORE_ARITHMETIC_UTILIZATION, nullptr, ACL_PROF_ACL_API | ACL_PROF_TASK_TIME | ACL_PROF_MSPROFTX); // 注意 ACL_PROF_MSPROFTX aclprofStart(config); // 瞬时事件 aclprofMark(loadMark); // 非嵌套范围(可跨线程) uint32_t rangeId = 0; aclprofRangeStart(preprocessRange, &rangeId); // ... 预处理逻辑 ... aclprofRangeStop(rangeId); // 嵌套范围(线程内) aclprofPush(outerRangePush); aclprofPush(innerRangePush); // ... 内层逻辑 ... aclprofPop(); // ... 外层逻辑 ... aclprofPop(); aclprofStop(config); aclprofDestroyStamp(stamp);

7.2 编译与运行

环境安装详情以及运行详情见 example 目录下的 README。运行步骤如下:

# ${install_root} 替换为 CANN 安装根目录,默认安装在 /usr/local/Ascend 目录 source ${install_root}/cann/set_env.sh export ASCEND_INSTALL_PATH=${install_root}/cann # Profiling 样例的 run.sh 还会读取 ASCEND_HOME_PATH,请一并设置为同一路径 export ASCEND_HOME_PATH=${install_root}/cann # 编译运行 bash run.sh

7.3 样例输出

[INFO] -------- Start -------- [INFO] Preprocess range start [INFO] Preprocess range stop [INFO] Nested operator dispatch range start [INFO] Nested operator dispatch range stop [INFO] Model execute start [INFO] Model execute end [INFO] -------- End --------

运行完成后,采集数据落盘到样例指定的./output目录(aclprofInit的第一个参数指定结果路径)。在 Profiling 解析并导出结果中,可通过msprof_tx summary数据查看本次打点的完整时间线:各 Stamp 的描述字符串、事件类型(Mark / Push/Pop / Start/Stop)、开始与结束时间戳等。

7.4 样例中的关键实践点

  • 样例的 main.cpp 将"创建 Stamp + 设置描述"封装为CreateStampWithMessage,并集中用StampSet管理多个 Stamp,结束时统一aclprofDestroyStamp——这是推荐的对象管理方式,避免漏释放;
  • 每个 Stamp 在创建后、使用前均校验非空,失败时立即aclprofDestroyStamp清理并返回,体现了正确的错误处理范式;
  • 在打点外围用aclprofGetStepTimestamp(stepInfo, ACL_STEP_START/END, stream)记录 step 边界,将业务打点与训练 step 对齐(相关接口见 19-01 数据采集接口)。

八、注意事项与常见问题

  1. 忘记使能采集类型aclprofCreateConfigdataTypeConfig必须包含ACL_PROF_MSPROFTX,否则打点数据不会被采集(样例中为ACL_PROF_ACL_API | ACL_PROF_TASK_TIME | ACL_PROF_MSPROFTX)。
  2. 接口顺序aclprofCreateStamp必须在aclprofStart之后、aclprofDestroyStamp必须在aclprofStop之前;违反顺序会得到EK0002类错误。
  3. 配对与生命周期:Push 之后必须 Pop、RangeStart 之后必须 RangeStop、PushEx 之后必须 Pop;否则会造成 Stamp 泄漏在栈/map 中或导致后续 Pop 弹栈失败。
  4. 消息长度aclprofSetStampTraceMessage的消息长度须小于 128 字节(源码中MAX_MSG_LEN = 128),aclprofMarkEx的消息长度最大支持 127 字符,超限会返回失败。
  5. 跨线程限制:Push/Pop 不能跨线程;跨线程场景请改用 RangeStart/RangeStop,其rangeId是进程唯一的,并以进程级 map 保存 Stamp。
  6. 不支持的场景:IPV350 产品不支持全部 msproftx 扩展接口;helper host 侧调用同样会被拒绝。
  7. 性能开销:Stamp 对象从预分配内存池中分配,打点数据通过 reporter 异步上报;但仍建议控制打点频率与消息长度,避免对热路径产生不必要的开销。

九、参考资料

  • msproftx 扩展接口官方文档(本文主体来源)
  • 数据采集接口(aclprofStart / aclprofStop 等)
  • 接口声明与公共结构体定义
  • 底层实现:MsprofTxManager
  • 接口适配层:msproftx_adaptor.cpp
  • msproftx 实战样例
  • aclError 错误码说明
  • 数据结构说明(aclprofEventAttributes)
  • Profiling 数据采集指南(开发指南)

【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 12:59:01

Cocos Creator构建Windows桌面版:从exe到安装包全流程实战指南

最近项目要发布Windows桌面版&#xff0c;产品那边要求给客户一个能双击安装的exe安装包&#xff0c;而不是让用户自己解压文件夹去点运行。我本来以为Cocos Creator构建个Windows平台也就点两下的事&#xff0c;真正走了一遍才发现&#xff0c;从编辑器构建出exe到做出一个合格…

作者头像 李华
网站建设 2026/9/19 12:52:51

Visual Studio 2022 实战安装指南:工作负载、版本选型与故障排查

1. 这不是“点下一步”的安装指南&#xff0c;而是你真正需要的 Visual Studio 2022 实战部署手册Visual Studio 2022 是目前 Windows 平台上最成熟、最完整的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它远不止是一个“写 C# 的工具”。如果你正在为一个新项目搭建…

作者头像 李华
网站建设 2026/9/19 12:51:09

比特币自托管终极安全指南:用松鼠备份构建防自己资产备份体系

1. 先聊透&#xff1a;为什么我持有比特币&#xff0c;最怕的却是自己很多人一听到“比特币 holder”这个词&#xff0c;第一反应是这人肯定天天盯盘、追涨杀跌、在币圈群里吹水。但说实话&#xff0c;真正的老 holder&#xff0c;尤其是从 312、519 那几轮大波动里活下来的人&…

作者头像 李华