简介cgminer 3.1.1 Windows 版是一份面向加密货币爱好者、旧平台维护者与挖矿程序研究者的 Windows 挖矿工具包主要用于多线程、多矿池环境下的比特币及其衍生币挖矿并提供 ATI GPU 监控、超频与风扇转速调节支持兼容 GPU、FPGA、ASIC 等硬件后端使用时需注意不要同时接入多条区块链。压缩包共 43 个文件、约 6.83MB包含可执行程序与动态链接库、OpenCL 内核脚本、FPGA 比特流及二进制文件以及配置示例、API 说明和多份技术文档覆盖安装构建、接口调用、SCRYPT 与 ASIC/FPGA 使用等主题。已有 560 人学习下载。借助示例配置、API 接口说明和各硬件后端文档读者可了解多池切换、设备监控与参数调整思路也能参考 OpenCL 内核和 FPGA 相关文件研究不同算法后端的组织方式适合旧版挖矿工具复现、排错与二次开发参考对学习旧版挖矿软件架构也有一定参考价值。1. 拿到 cgminer-3.1.1-windows 先别双击这个包在什么机器上还能跑cgminer 3.1.1 windows这个组合词在搜索框里出现的频率比它今天真正能跑起来的机器数量高得多。它是一个 C 写的、基于 OpenCL 的算力客户端界面是字符终端配置靠一个 JSON 文件和几十个命令行开关属于那个「显卡还能当通用计算设备用」的年代。它解决的问题很具体把 GPU 上的并行计算任务按固定节奏提交给远端作业端同时把每张卡的频率、温度、接受/拒绝计数实时打回屏幕。适合三类人手上有台装老驱动的工作机、想搞清楚 OpenCL 参数怎么影响吞吐、或者想拿一个真实的 C 工程练编译和 API 对接。不适合的是指望双击出结果的场景——这个包对驱动版本、目录结构、参数组合三者都挑任意一个不对表现都是「窗口一闪没了」。下面按「先让它跑起来再让它跑稳最后能远程看住」的顺序拆。2. 把 cgminer 3.1.1 跑起来解压路径、依赖 DLL 与第一次启动2.1 解压后先确认三件事主程序、配置模板、运行库Windows 版通常是预编译二进制不是让你现场编译的源码树。解压完不要急着把 exe 拖到桌面DLL 的搜索顺序是「exe 所在目录 → 系统目录 → PATH」一旦你把主程序单独挪走同目录的运行库就找不到了这是新人第一次翻车最常见的原因。典型发布包里能看到这几类文件文件/目录作用缺失后的表现cgminer.exe主程序字符界面 API 服务—*.dll运行库常见是 curl、pthread、zlib、OpenCL 加载层启动即闪退报 0xc000007b 或「找不到 xxx.dll」*.confJSON 格式的配置模板只能用全命令行参数启动长参数容易敲错*.bat启动脚本样例不影响运行但少了参数写法的参考README/*.txt参数与算法说明调参全靠猜效率极低建议路径定成纯英文、无空格例如D:\tools\cgminer-3.1.1\。带中文或空格的路径在加载 conf、写日志文件时会出现「文件明明在那却打不开」的玄学现象本质是命令行分词把空格当成了参数分隔符。2.2 第一次启动用 cmd不要用资源管理器双击双击启动失败时窗口会立刻关闭你连报错都看不到。正确做法是开一个 cmdcd进目录再执行错误信息就留在屏幕上了。:: 进入目录注意 /d 允许跨盘符切换 cd /d D:\tools\cgminer-3.1.1 :: 最小启动算法、作业端地址、凭据、四个核心调优参数 cgminer.exe --scrypt ^ -o stratumtcp://pool-host:3333 ^ -u worker-name ^ -p x ^ -I 13 -g 1 -w 256 --thread-concurrency 8192 ^ -T --log-file run.log参数逐个说明--scrypt切换算法分支。3.1.x 之后才把 scrypt 并进主线不加这个开关走的是另一套内核显存占用和参数含义完全不同这是最容易漏的一个。-o远端作业端地址stratumtcp://前缀表示走 stratum 协议后面的端口要和对方给的一致。-u/-p凭据。很多作业端对密码不校验随便填但用户名不能错。-I强度020scrypt 下有效区间大概 820越高显存访问越激进。-g每张卡起几组线程scrypt 一般 1设成 2 反而抢显存。-wwork group 大小必须是 64 的倍数常见 128 或 256。--thread-concurrency并发线程数直接决定显存占用后面单独讲。-T纯文本模式不走 ncurses 全屏日志能正常滚动排查阶段必开。--log-file落盘日志出问题时有据可查。启动成功后屏幕会分区刷新顶部是全局汇总运行时长、平均算力、接受/拒绝数中间是每个设备一行温度、风扇、频率、强度底部是作业端连接状态。终端里按Q退出按D切设备详情按P切作业端列表。字符界面看着粗糙但它刷新频率低、不占资源反而比图形界面更适合长时间挂着。2.3 把命令行固化成 cgminer.conf每次敲一长串参数不现实出错率也高。把参数搬进 JSON 配置文件启动时只给-c。{ pools: [ { url: stratumtcp://pool-host:3333, user: worker-name, pass: x }, { url: stratumtcp://backup-host:3333, user: worker-name, pass: x, quota: 1 } ], scrypt: true, intensity: 13, gpu-threads: 1, worksize: 256, thread-concurrency: 8192, lookup-gap: 2, temp-cutoff: 95, temp-overheat: 85, temp-target: 75, auto-fan: true, api-listen: true, api-port: 4028, api-allow: W:127.0.0.1, log-file: run.log }几个容易踩的格式点conf 里的值绝大多数写成字符串13而不是13虽然解析器对布尔值和数字有一定容忍度但混着写会出现「配置加载了却没生效」的假象pools是数组顺序即优先级quota控制切换权重scrypt是布尔值写true不带引号。启动命令就变成cgminer.exe -c cgminer.conf如果同时给了命令行参数和 conf命令行优先级更高会覆盖同名配置项。这个特性在调试时有用——你可以用 conf 固化一套稳定参数临时加-I 15试一下高一点的强度退出后 conf 不受影响。3. cgminer 参数调优-I、-g、-w 与 thread-concurrency 到底谁管谁3.1 从一次 OpenCL 内核调度看四个参数的分工要调参先得知道它们在硬件层面分别动的是什么。scrypt 这类算法是显存密集型每个并发线程在计算过程中要占一块固定大小的 scratchpad通常按每线程 128 KB 估算。所以thread-concurrency不是随便填的数字它直接乘出显存占用超过可用显存就是崩溃或驱动重置。四个参数的分工大致是thread-concurrencyTC一条提交里并发跑多少个线程决定显存占用的总量。-wworksize每个 work group 里多少个线程必须是 64 的整数倍影响调度粒度和 LDS 使用效率。-Iintensity内核内部每个线程做多少轮查找影响单线程的指令密度和寄存器压力。-ggpu-threads每张卡同时跑几条这样的流水线等于把上面三项再复制一份。它们的组合关系是相乘的所以调参不能四项一起动。血泪经验是先把g固定为 1把w固定为 256然后用 TC 卡住显存上限最后才用 I 往上顶。顺序反了你会在一堆变量里迷失每次崩了都说不清是谁的锅。3.2 按显存反推 thread-concurrency 的起步值算一下就知道上限在哪。以 2 GB 显存为例扣除显示输出和驱动自身占用可用按 1.7 GB 估除以每线程 128 KB1.7 * 1024 * 1024 KB / 128 KB ≈ 13926也就是说理论上限在一万四左右实际要留余量给驱动和桌面合成取 60%70% 比较稳。不同卡的建议起步值不是拍脑袋来的是照这个公式再按经验系数收一收显存TC 起步值-I起步值-wlookup-gap1 GB4096912822 GB81921325623 GB122881325624 GB 及以上16384152562lookup-gap是控制 scratchpad 里各轮数据之间间隔的作用类似调显存时序。默认 2 最稳改到 1 或 3 属于精调阶段的事先用 2 把所有变量跑通。表里的数字只是起点同一块芯片在不同驱动版本下最优值能差一档必须自己扫。还有一个硬约束TC最好能被w整除否则最后一次 work group 会不满员效率打折。8192 / 256 32整齐如果你把 TC 设成 8000除不尽尾组浪费就出现了。3.3 一套可复现的爬坡流程用 --runtime 做对照实验调参最怕「改了之后忘了原来多少」。稳定做法是每换一组参数固定跑一段时间把日志留下来对比。--runtime参数可以指定运行多少分钟后自动退出配合--log-file就成了一次可重复的实验。echo off setlocal enabledelayedexpansion set CGMD:\tools\cgminer-3.1.1\cgminer.exe set POOLstratumtcp://pool-host:3333 :: 固定 TC 和 w只扫 intensity每次跑 8 分钟 for %%I in (9 11 13 15 17) do ( echo testing intensity %%I %CGM% --scrypt -o %POOL% -u worker-name -p x ^ -I %%I -g 1 -w 256 --thread-concurrency 8192 ^ --runtime 8 -T --log-file log-I%%I.txt :: 间隔几秒让驱动彻底释放显存再进下一轮 timeout /t 10 /nobreak nul ) echo done, check log-I*.txt这段脚本的逻辑很直白外层循环只改-I其余参数锁死这样每一轮的差异只能归因于强度--runtime 8让每轮自动收尾不会挂在那里等你手动 CtrlC--log-file每轮一个独立文件事后可以横向比。跑完之后在日志里找汇总行重点看三个数平均算力、被拒比例、硬件错误数。判读标准我一般这么定算力涨了但硬件错误开始出现说明这一档已经过界退回去算力不涨反而拒单变多说明内核在空转也退回去只有在算力上升且错误数保持为 0 的那一档才是可用值。别贪最后一格那格通常是拿稳定性换的。同理可以再扫一轮 TC固定-I为上一轮的最优值TC从 4096 开始每档加 2048 往上走一旦出现驱动重置或程序退出上一档就是该卡的显存天花板。两轮扫完一张卡的参数画像就有了抄进 conf 即可。4. cgminer API 不是黑匣子4028 端口怎么开、怎么读、怎么当监控用4.1 两个开关--api-listen 与 --api-allow字符界面只能人盯着机器一多就不现实。cgminer 内置了一个 TCP 服务默认端口 4028收发都是单行 JSON以\0结尾。这个接口默认是关的要显式打开并且要配置允许访问的来源。cgminer.exe -c cgminer.conf ^ --api-listen ^ --api-port 4028 ^ --api-allow W:127.0.0.1,W:192.168.1.0/24--api-listen是总开关--api-port可以改成别的端口避免和同机其他服务打架--api-allow的格式是「权限:来源」W表示可写能执行切换、重启这类命令R表示只读。只给本机和内网段不要开成W:0.0.0.0/0这个接口没有任何认证谁能连上谁就能改你的运行状态。注意端口开了但 Windows 防火墙拦着本地能连、远程连不上这是第二个常见困惑点。排查时先在本机telnet 127.0.0.1 4028通了再查防火墙入站规则。4.2 用 Python 拉 summary / devs / pools协议简单到不需要任何 SDK一个 socket 就够。import json import socket def cgminer(command, host127.0.0.1, port4028, timeout3): 发送单条命令读回到 \\0 为止返回解析后的 dict。 payload json.dumps({command: command}) \n with socket.create_connection((host, port), timeouttimeout) as sock: sock.sendall(payload.encode(utf-8)) buf b while b\x00 not in buf: # 协议用 NUL 作为报文结束符 chunk sock.recv(4096) if not chunk: # 对端提前关闭避免死循环 break buf chunk body buf.split(b\x00, 1)[0] return json.loads(body.decode(utf-8, ignore)) if __name__ __main__: s cgminer(summary) print(算力:, s[SUMMARY][0][MHS av]) print(接受/拒绝:, s[SUMMARY][0][Accepted], s[SUMMARY][0][Rejected]) # devs 返回每张卡的独立状态用来定位「是哪张卡拖后腿」 for dev in cgminer(devs)[DEVS]: print(dev[GPU], dev[Temperature], dev[Intensity], dev[MHS av])几个实现细节返回值是{STATUS: [...], SUMMARY: [...]}这种结构命令名大写后作为键值一律是列表所以取第一条STATUS里有个STATUS字段S表示成功、E表示出错、W表示警告判断成败看这里而不是看有没有异常MHS av这个键名是历史遗留scrypt 下数值极小实际看的时候按 KH/s 理解更直观。4.3 三个值得长期盯的字段以及 switchpool 兜底监控不是把所有字段都打印出来那样只会刷屏。真正需要盯的是三个平均算力看趋势而不是绝对值。连续多个采样点下滑通常是散热降频或者作业端在发低难度任务。拒绝比例Rejected / (Accepted Rejected)。超过 2% 就该查了要么是本地时钟漂了要么是强度过高导致提交超时。温度这是唯一会导致硬件损伤的指标超过temp-overheat就该降频别指望auto-fan能救一切。作业端挂了要能自动切这是无人值守的前提def failover(): 遍历作业端发现当前优先级不可用就切到下一个。 pools cgminer(pools)[POOLS] current next((p for p in pools if p[Status] Alive), None) if current: return falive: {current[URL]} for p in sorted(pools, keylambda x: int(x[Priority])): if p[Status] ! Alive: cgminer(fswitchpool|{p[POOL]}) return fswitched to {p[URL]} return no pool availableswitchpool的参数是池序号不是 URL这个细节坑过不少人。切完之后建议隔十秒再读一次pools确认状态真的变了有些作业端切换后需要重新握手立刻读会看到还在Dead。5. 避坑与排查cgminer 3.1.1 在 Windows 上的五类翻车现场5.1 五条「现象 → 原因 → 解决」第一条双击 exe黑框一闪就没了。现象是窗口存在时间不到一秒什么都看不清。原因是流程根本没走到主循环——要么同目录缺 DLL要么参数解析失败要么路径里有中文。解决开 cmd 进目录执行报错会留下看到「找不到 xxx.dll」就补运行库看到参数错误就去掉所有可选参数先跑最小命令顺手把整个目录挪到纯英文路径下。第二条日志里出现No devices detected或clGetDeviceIDs failed。现象是程序能启动但设备列表是空的。原因通常是显卡驱动没装 OpenCL 运行时或者装的是纯显示驱动或者 32 位程序加载了 64 位的 OpenCL 加载层。解决重装厂商完整驱动包确认系统目录和程序目录下的 OpenCL 加载层位数与 exe 一致任务管理器里看进程是不是带 32 位标记。老版本程序对新架构显卡识别不出来也是常态这种情况换平台比死磕划算。第三条跑几分钟屏幕黑一下程序报错退出。这是 Windows 的 TDR 机制在起作用——显卡单次计算超过默认的 2 秒系统认为驱动挂死强制重置。挖矿内核本来就是长时占用撞上这个太正常了。解决顺序是先降-I一到两档、把-w提到 256多数情况能压到 2 秒以内还不行就降 TC 减少并发压力。改注册表延长超时属于最后手段会让真正的驱动故障也变成长时间黑屏风险自负我一般不推荐在生产机上这么做。第四条本机能连 4028另一台机器连不上。现象是telnet 127.0.0.1 4028通换成局域网 IP 就超时。原因是三选一没加--api-listen只写了端口没用、--api-allow没包含对方网段、Windows 防火墙拦了入站。解决依次确认启动日志里有没有「API listening」这行、allow 列表里有没有对方 IP 段、防火墙有没有放行该端口的入站规则。三步都过了一般就通了。第五条改了 conf重启后参数没变。现象是文件明明保存了界面上的强度还是老值。原因可能是程序实际加载的是另一个同名 conf工作目录不对、JSON 里键名拼错被静默忽略、或者启动命令行里还带着会覆盖 conf 的旧参数。解决用-T启动看回显程序在初始化阶段会打印实际生效的关键参数再不行就在 conf 里故意写一个非法值如果程序没报错说明这个文件压根没被读到。5.2 出问题先看日志的哪几行排查效率高低差别就在知不知道该看哪里。启动阶段的日志看三样设备枚举结果识别到几张卡、每张卡的名称、作业端连接结果连上还是超时、实际生效的参数回显。运行阶段的日志看两样每次提交的结果接受/拒绝/过期以及温度触发的降频事件。:: 找所有与设备相关的行 findstr /i device GPU detected run.log :: 找拒绝和错误 findstr /i rejected error stale run.log :: 找温度与降频 findstr /i temp throttl fan run.log提示把-T和--log-file一起用。纯文本模式下日志是逐行追加的全屏模式会不断重绘终端重定向出来的文件里全是控制字符事后没法读。还有一个容易被忽略的点日志文件默认是追加写的。同一目录下反复启动旧日志会越滚越大找当次记录时容易看串行。习惯做法是每次实验前把旧的挪走或者改个名别让两次运行的数据混在一个文件里。6. 老版本的进阶用法把参数验证做成三层校验参数抄进 conf 不等于生效生效不等于稳定稳定不等于最优。这三件事要分开验证我一般做成三层每层都有明确的判据。层级做什么判据不通过怎么办第一层配置回显-T启动看初始化日志关键参数与 conf 一致查工作目录、键名拼写、命令行覆盖第二层设备状态调devs接口读每卡字段Intensity、Thread Concurrency与预期一致说明该卡没吃到配置查是否被单独限制第三层运行质量跑满 30 分钟看日志均值硬件错误为 0拒绝比例 2%回退一档强度或降低 TC第一层最容易被跳过但它是唯一能证明「程序读到了你的文件」的证据。第二层用来抓「多卡不同配置」的问题——cgminer 支持按设备序号单独指定参数一旦某张卡被单独限制过全局参数对它就不生效了光看汇总数据发现不了。第三层是唯一有统计意义的验证短时间跑出来的算力波动很大至少半小时再下结论。再补一个实用技巧把 API 拉数和参数实验合到一个脚本里跑完自动出对比表省得手工翻日志。import time from statistics import mean def bench(minutes10, sample30): 采样指定时长返回均值与稳定性指标。 speeds, rejects [], 0 deadline time.time() minutes * 60 while time.time() deadline: s cgminer(summary)[SUMMARY][0] speeds.append(float(s[MHS av])) rejects int(s[Rejected]) time.sleep(sample) avg mean(speeds) # 用极差比衡量稳定性比值越小越稳 spread (max(speeds) - min(speeds)) / avg if avg else 0 return {avg: round(avg, 3), spread: round(spread, 3), rejected: rejects}这段的判读逻辑是avg用来横向比不同参数组合spread用来判断这一档稳不稳——算力忽高忽低通常意味着散热在边界上反复触发降频或者显存已经接近满载开始出现重试。spread超过 0.15 我就认为这档不可用哪怕它的均值最好看。拒绝数只在整段实验里累计不和算力放一起比。最后说个我自己的教训。早年调这类老程序我总想一步到位找到「最佳参数」结果是在一堆变量里反复横跳改完 A 忘 B出问题连回滚到哪都不知道。后来强制自己走一遍「固定三项、只动一项、每轮留日志、跑满半小时」的流程看着慢实际比乱试快得多而且每一步都有据可查。现在哪怕只是改一个数字我也会先把当前的 conf 复制一份带时间戳的备份再动手——这个习惯救过我很多次。希望帮到你。本文还有配套的精品资源点击获取