当前位置: 首页 > article >正文

CANN Profiling 与性能分析:定位训练与推理瓶颈

一、为什么需要 Profiling1.1 性能问题的来源深度学习训练和推理的性能瓶颈可能来自多个环节数据准备慢导致 GPU 空闲、模型算子计算慢成为瓶颈、内存拷贝频繁拖累整体、通信带宽受限拖慢分布式训练。不同瓶颈的优化方法完全不同错误的优化方向不仅浪费 effort还可能引入新的问题。Profiling 的目的是先定位再优化用数据说话而非凭直觉猜测。1.2 CANN Profiling 工具链┌──────────────────────────────────────────────────┐ │ CANN Profiling 工具链 │ ├──────────────────────────────────────────────────┤ │ ascend-snCLI工具 │ │ ├── report生成性能报告 │ │ ├── analyze分析瓶颈 │ │ └── compare对比两次运行 │ │ │ │ ProfilerPython接口 │ │ ├── start/stop控制采集 │ │ ├── export导出数据 │ │ └── view可视化 │ └──────────────────────────────────────────────────┘1.3 Profiling 能解决什么问题问题场景Profiling 能发现训练速度低于预期数据加载瓶颈、算子耗时分布多卡训练加速比低通信时间占比、负载均衡问题推理延迟高哪些算子最耗时、显存拷贝开销显存占用异常哪些算子占用最多显存新优化效果不明显优化前后对比量化差异二、基础 Profiling 配置2.1 环境变量配置Profiling 通过环境变量控制采集范围和输出路径8.1 及之前基础配置# 启用 Profiling只采集算子执行时间exportASCEND_PROFILING_ENABLE1exportASCEND_PROFILING_OUTPUT_PATH/workspace/profiling_data# 运行训练python train.py8.2 新增精细化配置# 启用完整 Profiling算子通信内存exportASCEND_PROFILING_ENABLE1exportASCEND_PROFILING_OUTPUT_PATH/workspace/profiling_data# 采样配置exportASCEND_PROFILING_FREQ1000# 采样频率exportASCEND_PROFILING_TRACE_LEVEL3# 跟踪级别1-3# 关键算子采集减少数据量exportASCEND_PROFILING_OP_LISTMatMul,Conv2d,LayerNorm# 通信 ProfilingexportASCEND_HCCL_PROFILING_ENABLE1# 内存 ProfilingexportASCEND_MEMORY_PROFILING_ENABLE1python train.py2.2 Profiler Python 接口基础采集fromascend.profilerimportProfiler,ProfilerConfig# 配置 ProfilerconfigProfilerConfig(output_path/workspace/profiling,trace_ops[MatMul,Conv2d,LayerNorm,Softmax],enable通信True,# 8.2 新增enable_memoryTrue,# 8.2 新增sample_interval100# 采样间隔微秒)profilerProfiler(config)# 采集训练forepochinrange(num_epochs):profiler.start()forbatchindataloader:outputmodel(batch)lossloss_fn(output,target)loss.backward()optimizer.step()profiler.stop()# 每个 epoch 采集一次profiler.save()print(fProfiling data saved to{config.output_path})2.3 关键指标解读Profiling 输出的核心指标指标含义健康范围GPUTime算子实际执行时间-HostTime数据准备时间应远小于 GPUTimeCalls算子调用次数-AvgTime平均单次执行时间-InputSize输入数据大小-OutputSize输出数据大小-算子级别耗时分布示例算子 调用次数 总耗时 平均耗时 占比 MatMul 1,024 2,048ms 2.0ms 38.2% Conv2d 512 1,024ms 2.0ms 19.1% LayerNorm 512 768ms 1.5ms 14.3% Softmax 256 512ms 2.0ms 9.5% ReLU 1,024 256ms 0.25ms 4.8%三、训练 Profiling 分析3.1 数据加载瓶颈诊断训练中数据加载常成为瓶颈使用 Profiler 区分计算和数据准备时间fromascend.profilerimportProfiler profilerProfiler(output_path/workspace/profiling)forbatch_idx,batchinenumerate(dataloader):data_starttime.time()# 数据传输到 NPUdata,targetbatch[input].npu(),batch[label].npu()data_timetime.time()-data_start# 模型计算profiler.start_op(forward)outputmodel(data)lossloss_fn(output,target)profiler.stop_op(forward)profiler.start_op(backward)loss.backward()profiler.stop_op(backward)profiler.start_op(optimizer)optimizer.step()profiler.stop_op(optimizer)# 记录数据加载时间profiler.log_metric(data_time,data_time)ifbatch_idx%1000:print(profiler.summary())8.1 vs 8.2 数据加载瓶颈对比配置数据时间计算时间瓶颈8.1 单线程 DataLoader45ms55ms数据8.2 num_workers812ms55ms计算8.2 prefetch28ms55ms计算3.2 算子耗时分析定位最耗时的算子是优化的第一步# 运行 Profiling 并生成报告python train.py--profile# 生成算子级分析报告ascend-sn analyze\--input/workspace/profiling\--output/workspace/profiling/report.html\--op_time_threshold1.0# 只显示耗时 1ms 的算子# 打开报告open/workspace/profiling/report.html8.2 新增算子融合分析# 分析算子融合效果ascend-sn analyze\--input/workspace/profiling\--fusion_reportTrue# 生成融合分析报告# 输出示例算子融合分析: Conv2d BiasAdd ReLU → fused_ops 融合率:78% 融合前耗时: 512ms 融合后耗时: 410ms 节省: 102ms(19.9%)3.3 显存瓶颈分析8.2 新增显存 Profiling追踪各算子的显存占用exportASCEND_MEMORY_PROFILING_ENABLE1python train.py# 生成显存分析报告ascend-sn analyze\--input/workspace/profiling\--memory_reportTrue显存分析报告示例算子 保留显存 峰值显存 申请次数 MatMul 1.2 GB 1.5 GB 1,024 Embedding 0.8 GB 0.8 GB 1 LayerNorm 0.4 GB 0.6 GB 512 总显存 2.4 GB 2.8 GB显存热点定位# 代码中添加显存追踪forname,moduleinmodel.named_modules():ifisinstance(module,nn.Linear):# 追踪某一层的显存占用memory_beforetorch.npu.max_memory_allocated()outputmodule(input)memory_aftertorch.npu.max_memory_allocated()print(f{name}:{memory_after-memory_before:.2f}MB)四、通信 Profiling多卡训练4.1 HCCL 通信分析多卡训练中通信往往是性能瓶颈需要 Profiling 区分计算和通信时间8.1 及之前粗粒度# 只能看到总时间无法区分计算和通信exportHCCL_TRACE_LEVEL1python train.py8.2 新增细粒度通信分析# 开启 HCCL 详细 ProfilingexportHCCL_TRACE_LEVEL3exportHCCL_PROFILING_OUTPUT/workspace/hccl_profiling python train.py# 生成通信分析报告ascend-sn analyze\--input/workspace/hccl_profiling\--comm_reportTrue通信分析报告通信原语 调用次数 总耗时 平均耗时 通信占比 AllReduce 512 1,024ms 2.0ms 32.5% Broadcast 128 256ms 2.0ms 8.1% AllGather 64 128ms 2.0ms 4.1% 总通信时间 44.7%4.2 通信瓶颈诊断流程# 在训练循环中添加时间戳记录importtimeforbatchindataloader:step_starttime.time()# 数据加载data_loading_timetime.time()-step_start# 前向forward_starttime.time()outputmodel(data)lossloss_fn(output,target)forward_timetime.time()-forward_start# 反向backward_starttime.time()loss.backward()backward_timetime.time()-backward_start# 通信同步comm_starttime.time()torch.distributed.all_reduce(gradients)comm_timetime.time()-comm_start# optimizeroptimizer_starttime.time()optimizer.step()optimizer_timetime.time()-optimizer_start total_timetime.time()-step_startiflocal_rank0:print(f Step{batch_idx}: Data:{data_loading_time:.3f}s ({data_loading_time/total_time*100:.1f}%) Forward:{forward_time:.3f}s ({forward_time/total_time*100:.1f}%) Backward:{backward_time:.3f}s ({backward_time/total_time*100:.1f}%) Comm:{comm_time:.3f}s ({comm_time/total_time*100:.1f}%) Optimizer:{optimizer_time:.3f}s ({optimizer_time/total_time*100:.1f}%) )通信占比诊断标准通信占比结论优化方向 15%正常计算瓶颈优化算子15-30%轻微通信瓶颈梯度压缩 30%严重通信瓶颈通信优化或并行策略调整 50%极严重重新设计并行策略五、推理 Profiling 分析5.1 推理延迟分解推理优化前需要知道时间花在哪里importtimeclassInferenceProfiler:def__init__(self,model):self.modelmodel self.timings{}defprofile(self,input_data,num_runs100):# 预热for_inrange(10):_self.model.predict(input_data)# 正式测试for_inrange(num_runs):starttime.time()# 数据拷贝copy_starttime.time()input_npuinput_data.npu()copy_timetime.time()-copy_start# 模型推理infer_starttime.time()outputself.model.predict(input_npu)infer_timetime.time()-infer_start# 结果拷贝output_copy_starttime.time()output_cpuoutput.cpu()output_copy_timetime.time()-output_copy_start totaltime.time()-start self.timings[copy]self.timings.get(copy,0)copy_time self.timings[inference]self.timings.get(inference,0)infer_time self.timings[output_copy]self.timings.get(output_copy,0)output_copy_time# 统计nnum_runsprint(f 推理延迟分解{n}次平均: 数据拷贝:{self.timings[copy]/n*1000:.2f}ms ({self.timings[copy]/self.timings[copy]*100:.1f}%) 模型推理:{self.timings[inference]/n*1000:.2f}ms ({self.timings[inference]/(self.timings[copy]self.timings[inference]self.timings[output_copy])*100:.1f}%) 结果拷贝:{self.timings[output_copy]/n*1000:.2f}ms ({self.timings[output_copy]/(self.timings[copy]self.timings[inference]self.timings[output_copy])*100:.1f}%) 总延迟:{(self.timings[copy]self.timings[inference]self.timings[output_copy])/n*1000:.2f}ms )profilerInferenceProfiler(model)profiler.profile(test_input)5.2 推理吞吐量分析defmeasure_throughput(model,input_shape,batch_sizes[1,4,8,16,32]):测量不同 batch size 的吞吐量results[]forbsinbatch_sizes:test_inputnp.random.randn(bs,*input_shape).astype(np.float32)# 预热for_inrange(10):_model.predict(test_input)# 测量latencies[]for_inrange(100):starttime.time()_model.predict(test_input)latencies.append(time.time()-start)avg_latencynp.mean(latencies)throughputbs/avg_latency results.append({batch_size:bs,avg_latency:avg_latency*1000,# msthroughput:throughput})print(fBatch{bs:2d}: latency{avg_latency*1000:6.2f}ms, throughput{throughput:7.1f}img/s)returnresults resultsmeasure_throughput(model,(3,224,224))# 找最优 batchbestmax(results,keylambdax:x[throughput])print(f\n最优配置: batch_size{best[batch_size]}, throughput{best[throughput]:.1f}img/s)5.3 算子级推理分析# 推理 Profiling 命令atc--model/path/to/model.onnx\--framework5\--output/path/to/model\--soc_versionAscend310\--profiling_modememory# 内存 Profiling--profiling_output/workspace/infer_profiling# 查看瓶颈算子ascend-sn analyze\--input/workspace/infer_profiling\--top_k20# 显示 Top 20 耗时算子六、Profiling 报告解读6.1 报告结构CANN Profiling 报告包含以下部分Profiling Report ├── 执行概览 │ ├── 总耗时 │ ├── 算子总数 │ └── 时间分布饼图 ├── 算子分析 │ ├── Top 耗时算子 │ ├── 算子融合分析 │ └── 算子调用分析 ├── 通信分析多卡 │ ├── AllReduce 统计 │ └── 通信占比 ├── 显存分析 │ ├── 峰值显存 │ └── 显存热点 └── 优化建议 ├── 优先级高 ├── 优先级中 └── 优先级低6.2 关键优化建议Profiling 报告会自动生成优化建议问题建议预期收益数据加载占比高增加 num_workers使用 pin_memory提升 20-30%AllReduce 占比高启用梯度压缩或调整通信拓扑提升 15-40%小算子多开启算子融合提升 10-25%显存接近上限启用混合精度或 gradient checkpointing显存 -50%单算子耗时长检查是否使用最优 core_type提升 10-30%七、自动化 Profiling 脚本7.1 训练 Profiling 脚本#!/usr/bin/env python3 CANN 训练 Profiling 自动脚本 importosimportargparsefromascend.profilerimportProfiler,ProfilerConfigdefmain():parserargparse.ArgumentParser()parser.add_argument(--output,default/workspace/profiling)parser.add_argument(--ops,nargs,default[MatMul,Conv2d,LayerNorm])parser.add_argument(--epochs,typeint,default1)argsparser.parse_args()# 创建 ProfilerconfigProfilerConfig(output_pathargs.output,trace_opsargs.ops,enable_memoryTrue,enable通信True)profilerProfiler(config)# 构建模型modelbuild_model().npu()# Profiling 训练forepochinrange(args.epochs):profiler.start()forbatch_idx,batchinenumerate(dataloader):data,targetbatch[input].npu(),batch[label].npu()outputmodel(data)lossloss_fn(output,target)loss.backward()optimizer.step()ifbatch_idx%1000:profiler.save(intermediateTrue)profiler.stop()profiler.save()print(fProfiling complete. See{args.output})if__name____main__:main()7.2 使用方法# 基础 Profilingpython profiling.py--output/workspace/my_profile# 指定要追踪的算子python profiling.py--opsMatMul Conv2d LayerNorm Softmax# 多 epoch Profilingpython profiling.py--epochs3# 生成报告ascend-sn report--input/workspace/my_profile--output/workspace/my_report.html八、常见问题问题原因解决方案Profiling 数据为空环境变量未设置检查 ASCEND_PROFILING_ENABLE1报告生成失败数据损坏重新运行 Profiling显存溢出Profiling 本身占用大量显存减小采样频率或关闭 memory profiling性能反而下降Profiling 开销生产环境关闭 Profiling报告无法打开路径中文或特殊字符改用纯英文路径相关仓库ascend-toolkit- Profiling 工具和报告生成器 https://gitee.com/ascend/ascend-toolkitatc- 模型转换工具含 Profiling 配置 https://gitee.com/ascend/atctorch_npu- PyTorch Profiler 接口 https://gitee.com/ascend/torch_npu

相关文章:

CANN Profiling 与性能分析:定位训练与推理瓶颈

一、为什么需要 Profiling 1.1 性能问题的来源 深度学习训练和推理的性能瓶颈可能来自多个环节:数据准备慢导致 GPU 空闲、模型算子计算慢成为瓶颈、内存拷贝频繁拖累整体、通信带宽受限拖慢分布式训练。不同瓶颈的优化方法完全不同,错误的优化方向不仅浪…...

机器学习评价指标之基础指标与综合指标

基础指标评价指标的计算方法在两种方法中有一些差异,但它们都提供了对模型性能的有效度量,用于评估模型在多分类任务中的表现。具体选择哪种方法取决于任务需求、数据特点以及模型训练的策略。对于直接对多个类别进行预测的多分类模型,准确率…...

Fusion360新手必看:这10个隐藏快捷键和技巧,让你建模效率翻倍

Fusion360效率革命:10个被低估的实战技巧与深度应用 第一次打开Fusion360时,我被它复杂的界面吓到了——工具栏密密麻麻的图标,嵌套多层的右键菜单,还有那些隐藏在角落里的功能选项。直到一位资深用户向我演示了如何用长按左键快…...

碧蓝航线全皮肤解锁终极指南:Perseus补丁五分钟快速上手

碧蓝航线全皮肤解锁终极指南:Perseus补丁五分钟快速上手 【免费下载链接】Perseus Azur Lane scripts patcher. 项目地址: https://gitcode.com/gh_mirrors/pers/Perseus 还在为碧蓝航线中那些精美的舰娘皮肤需要付费解锁而烦恼吗?想要免费体验所…...

布局先行、技术深耕:国内端侧AI企业抢滩机器人与具身智能赛道

具身智能作为AI与物理世界交互的核心方向,正成为工业智能化、人形机器人落地的关键抓手。国内一批端侧AI企业凭借原生技术优势,早早入局机器人与具身智能领域,以全栈技术、规模化落地与生态共建,抢占行业先发优势。其中&#xff0…...

告别低效编程:在PyCharm 2024.1中配置Baidu Comate的保姆级教程(含快捷键设置)

告别低效编程:在PyCharm 2024.1中配置Baidu Comate的保姆级教程(含快捷键设置) 作为一名长期使用PyCharm进行Python开发的工程师,我深刻体会到重复性编码工作对创造力的消耗。直到遇见Baidu Comate——这款能与IDE深度集成的AI编码…...

想选靠谱的呼入语音机器人?这三个核心维度别忽略

电商大促期间客服热线占线不断,客户等待几分钟后愤然挂断;夜间咨询无人值守,潜在商机白白流失;传统语音机器人只会机械重复 “请按 1”,遇到稍微复杂的问题就答非所问…… 这些场景几乎是每个企业客服部门的日常痛点。…...

东南大学论文模板终极指南:3步搞定毕业设计排版难题

东南大学论文模板终极指南:3步搞定毕业设计排版难题 【免费下载链接】SEUThesis 东南大学论文模板 项目地址: https://gitcode.com/gh_mirrors/seu/SEUThesis 对于每一位东南大学的学子来说,毕业季最头疼的往往不是论文内容本身,而是繁…...

DataRoom:一站式开源大屏设计器终极指南,快速构建专业数据可视化大屏

DataRoom:一站式开源大屏设计器终极指南,快速构建专业数据可视化大屏 【免费下载链接】DataRoom 🔥基于SpringBoot、MyBatisPlus、ElementUI、G2Plot、Echarts等技术栈的大屏设计器,具备目录管理、DashBoard设计、预览能力&#x…...

WeChatFerry微信机器人完整指南:构建企业级智能自动化助手

WeChatFerry微信机器人完整指南:构建企业级智能自动化助手 【免费下载链接】WeChatFerry 微信机器人,可接入DeepSeek、Gemini、ChatGPT、ChatGLM、讯飞星火、Tigerbot等大模型。微信 hook WeChat Robot Hook. 项目地址: https://gitcode.com/GitHub_Tr…...

Bilibili-Evolved:彻底改造你的B站体验!新手必看的个性化增强指南

Bilibili-Evolved:彻底改造你的B站体验!新手必看的个性化增强指南 【免费下载链接】Bilibili-Evolved 强大的哔哩哔哩增强脚本 项目地址: https://gitcode.com/gh_mirrors/bi/Bilibili-Evolved 你是否厌倦了B站千篇一律的界面?是否觉得…...

DCIM管理系统是什么?它的应用价值与关键功能有哪些?

DCIM管理系统的定义与功能概述 是现代数据中心重要的工具,目的是融合IT管理与设备监控,进而实现高效的容量规划与设备维护。这个系统的核心组件包括实时监控、资产管理及环境监控功能,利用综合运用这些工具,操作人员能够快速识别…...

CSerialPort 4.3.2 保姆级集成指南:5分钟让你的QT/MFC/Electron项目拥有稳定串口功能

CSerialPort 4.3.2 全栈集成实战:从QT到Electron的跨平台串口方案 在工业控制、物联网设备调试和嵌入式系统开发中,串口通信作为最基础也最可靠的数据传输方式之一,至今仍发挥着不可替代的作用。然而,不同操作系统提供的串口API差…...

5分钟快速上手:Parsec VDD虚拟显示器终极指南,解锁Windows显示新境界

5分钟快速上手:Parsec VDD虚拟显示器终极指南,解锁Windows显示新境界 【免费下载链接】parsec-vdd ✨ Perfect virtual display for game streaming 项目地址: https://gitcode.com/gh_mirrors/pa/parsec-vdd 你是否遇到过这样的困扰?…...

Nodejs后端服务集成Taotoken实现智能客服对话

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 Node.js 后端服务集成 Taotoken 实现智能客服对话 为客服系统引入智能对话能力,是提升服务效率与用户体验的有效路径。…...

龙芯LoongArch开发板实战:从2K0500到3A5000的嵌入式开发指南

1. 项目概述:当国产龙芯遇上嵌入式开发板最近几年,国产芯片的讨论热度一直很高,但很多开发者朋友可能和我当初一样,感觉它们离实际的嵌入式项目开发还有点距离。要么是资料难找,要么是生态工具链不成熟,上手…...

3分钟上手BetterNCM:网易云音乐插件管理的终极解决方案

3分钟上手BetterNCM:网易云音乐插件管理的终极解决方案 【免费下载链接】BetterNCM-Installer 一键安装 Better 系软件 项目地址: https://gitcode.com/gh_mirrors/be/BetterNCM-Installer 还在为网易云音乐PC版功能单一而烦恼吗?想要解锁更多个性…...

抖音批量下载助手:高效构建个人视频素材库的完整解决方案

抖音批量下载助手:高效构建个人视频素材库的完整解决方案 【免费下载链接】douyinhelper 抖音批量下载助手 项目地址: https://gitcode.com/gh_mirrors/do/douyinhelper 在内容创作成为主流表达方式的今天,视频素材的获取和管理成为创作者面临的核…...

STM32H7驱动AD7606实战:从硬件连接到代码调试,搞定8路并行数据采集

STM32H7驱动AD7606实战:从硬件连接到代码调试,搞定8路并行数据采集 在工业测量、医疗设备和自动化测试系统中,多通道高精度数据采集一直是工程师面临的挑战。AD7606作为一款16位8通道同步采样ADC,以其出色的性能和稳定性成为众多…...

5大核心功能深度解析:Akebi-GC游戏辅助工具完整使用指南

5大核心功能深度解析:Akebi-GC游戏辅助工具完整使用指南 【免费下载链接】Akebi-GC (Fork) The great software for some game that exploiting anime girls (and boys). 项目地址: https://gitcode.com/gh_mirrors/ak/Akebi-GC Akebi-GC是一款功能强大的游戏…...

从零玩转 Linux:网络配置、软件安装及 Docker 实战

下载镜像地址 一、基础命令篇 显示网络状态工具 netstat -nltup #显示当前服务以及端口信息等 查看某个端口是否开启 1.2.1、使用 netstat 命令 sudo netstat -tuln | grep 80 1.2.2、使用 ss 命令 sudo ss -tuln | grep 80 1.2.3、使用 lsof 命令 sudo lsof -i :80 1.2.4、使用…...

别再裸发ROS图像了!image_transport保姆级教程:从压缩传输到参数调优,一次搞定

别再裸发ROS图像了!image_transport保姆级教程:从压缩传输到参数调优,一次搞定 在机器人视觉开发中,图像传输往往是性能瓶颈的关键所在。许多开发者习惯性地使用ros::Publisher/Subscriber直接处理图像数据,却不知这种…...

拆解Autosar NM报文:从0x600到0x6FF,手把手教你读懂CAN网络里的‘心跳包’

Autosar网络管理报文深度解析:从0x600到0x6FF的实战指南 当你第一次打开主机厂的网络管理规范文档,看到满屏的十六进制地址和比特位定义时,是否感到一头雾水?本文将化身你的"技术显微镜",带你逐字节拆解Auto…...

2026年腾讯云OpenClaw/Hermes Agent配置Token Plan搭建保姆教程

2026年腾讯云OpenClaw/Hermes Agent配置Token Plan搭建保姆教程。OpenClaw是开源的个人AI助手,Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流 AI 工具&…...

FigmaCN终极指南:3分钟实现Figma界面全中文汉化的完整教程

FigmaCN终极指南:3分钟实现Figma界面全中文汉化的完整教程 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma的英文界面而烦恼吗?作为一名中文设计师&a…...

3分钟解决iPhone网络共享驱动问题:Windows用户终极指南

3分钟解决iPhone网络共享驱动问题:Windows用户终极指南 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.com/gh_mi…...

从账单明细看Taotoken计费模式的透明与可追溯性

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 从账单明细看Taotoken计费模式的透明与可追溯性 对于将大模型API集成到产品中的团队而言,成本控制与核算是一个核心的工…...

Steam创意工坊下载难题终结者:WorkshopDL让你的模组下载从未如此简单

Steam创意工坊下载难题终结者:WorkshopDL让你的模组下载从未如此简单 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 还在为想玩Steam创意工坊的模组却没有Steam账号…...

避坑指南:在Ubuntu 20.04上配置VNC远程桌面,为什么我推荐UltraVNC Viewer而不是TigerVNC?

Ubuntu 20.04远程桌面配置:为什么UltraVNC Viewer成为技术中坚的首选? 在Linux桌面环境远程管理的世界里,VNC协议就像一位历经沧桑的老兵,依然活跃在企业运维、远程开发和混合办公的第一线。Ubuntu 20.04 LTS作为长期支持版本&…...

CH341驱动安装避坑指南:为什么你的串口能识别,但I2C/SPI功能却用不了?

CH341驱动安装避坑指南:为什么你的串口能识别,但I2C/SPI功能却用不了? 刚拿到CH341模块时,很多开发者都会遇到一个诡异现象:USB转串口功能一切正常,但切换到I2C或SPI模式时,设备管理器里却怎么也…...