Browse Source

dynclock: Split dynamic clocking algorithm out of Ztex driver

Luke Dashjr 13 years ago
parent
commit
76e774b1bd
7 changed files with 158 additions and 77 deletions
  1. 4 0
      Makefile.am
  2. 1 0
      configure.ac
  3. 23 48
      driver-ztex.c
  4. 78 0
      dynclock.c
  5. 32 0
      dynclock.h
  6. 17 18
      libztex.c
  7. 3 11
      libztex.h

+ 4 - 0
Makefile.am

@@ -78,6 +78,10 @@ if NEED_FPGAUTILS
 bfgminer_SOURCES += fpgautils.c fpgautils.h
 endif
 
+if NEED_DYNCLOCK
+bfgminer_SOURCES += dynclock.c dynclock.h
+endif
+
 if HAS_BITFORCE
 bfgminer_SOURCES += driver-bitforce.c
 

+ 1 - 0
configure.ac

@@ -252,6 +252,7 @@ fi
 AC_CONFIG_SUBDIRS([libblkmaker])
 
 AM_CONDITIONAL([NEED_LIBBLKMAKER], [true])
+AM_CONDITIONAL([NEED_DYNCLOCK], [test x$ztex != xno])
 AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono])
 AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])

+ 23 - 48
driver-ztex.c

@@ -27,6 +27,7 @@
 #include <unistd.h>
 #include <sha2.h>
 
+#include "dynclock.h"
 #include "fpgautils.h"
 #include "miner.h"
 #include "libztex.h"
@@ -121,52 +122,29 @@ static void ztex_detect()
 	noserial_detect(ztex_api.dname, ztex_autodetect);
 }
 
-static bool ztex_updateFreq(struct libztex_device* ztex)
+static bool ztex_change_clock_func(struct thr_info *thr, int bestM)
 {
-	int i, maxM, bestM;
-	double bestR, r;
-
-	for (i = 0; i < ztex->freqMaxM; i++)
-		if (ztex->maxErrorRate[i + 1] * i < ztex->maxErrorRate[i] * (i + 20))
-			ztex->maxErrorRate[i + 1] = ztex->maxErrorRate[i] * (1.0 + 20.0 / i);
-
-	maxM = 0;
-	while (maxM < ztex->freqMDefault && ztex->maxErrorRate[maxM + 1] < LIBZTEX_MAXMAXERRORRATE)
-		maxM++;
-	while (maxM < ztex->freqMaxM && ztex->errorWeight[maxM] > 150 && ztex->maxErrorRate[maxM + 1] < LIBZTEX_MAXMAXERRORRATE)
-		maxM++;
-
-	bestM = 0;
-	bestR = 0;
-	for (i = 0; i <= maxM; i++) {
-		r = (i + 1 + (i == ztex->freqM? LIBZTEX_ERRORHYSTERESIS: 0)) * (1 - ztex->maxErrorRate[i]);
-		if (r > bestR) {
-			bestM = i;
-			bestR = r;
-		}
-	}
+	struct libztex_device *ztex = thr->cgpu->device_ztex;
 
-	if (bestM != ztex->freqM) {
-		ztex_selectFpga(ztex);
-		libztex_setFreq(ztex, bestM);
-		ztex_releaseFpga(ztex);
-	}
+	ztex_selectFpga(ztex);
+	libztex_setFreq(ztex, bestM);
+	ztex_releaseFpga(ztex);
 
-	maxM = ztex->freqMDefault;
-	while (maxM < ztex->freqMaxM && ztex->errorWeight[maxM + 1] > 100)
-		maxM++;
-	if ((bestM < (1.0 - LIBZTEX_OVERHEATTHRESHOLD) * maxM) && bestM < maxM - 1) {
+	return true;
+}
+
+static bool ztex_updateFreq(struct thr_info *thr)
+{
+	struct libztex_device *ztex = thr->cgpu->device_ztex;
+	bool rv = dclk_updateFreq(&ztex->dclk, ztex_change_clock_func, thr);
+	if (unlikely(!rv)) {
 		ztex_selectFpga(ztex);
 		libztex_resetFpga(ztex);
 		ztex_releaseFpga(ztex);
-		applog(LOG_ERR, "%s: frequency drop of %.1f%% detect. This may be caused by overheating. FPGA is shut down to prevent damage.",
-		       ztex->repr, (1.0 - 1.0 * bestM / maxM) * 100);
-		return false;
 	}
-	return true;
+	return rv;
 }
 
-
 static bool ztex_checkNonce(struct libztex_device *ztex,
                             struct work *work,
                             struct libztex_hash_data *hdata)
@@ -191,7 +169,7 @@ static bool ztex_checkNonce(struct libztex_device *ztex,
 	sha2(swap, 80, hash1, false);
 	sha2(hash1, 32, hash2, false);
 	if (htobe32(hash2_32[7]) != ((hdata->hash7 + 0x5be0cd19) & 0xFFFFFFFF)) {
-		ztex->errorCount[ztex->freqM] += 1.0 / ztex->numNonces;
+		dclk_errorCount(&ztex->dclk, 1.0 / ztex->numNonces);
 		applog(LOG_DEBUG, "%s: checkNonce failed for %0.8X", ztex->repr, hdata->nonce);
 		return false;
 	}
@@ -285,8 +263,7 @@ static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 			break;
 		}
 
-		ztex->errorCount[ztex->freqM] *= 0.995;
-		ztex->errorWeight[ztex->freqM] = ztex->errorWeight[ztex->freqM] * 0.995 + 1.0;
+		dclk_gotNonces(&ztex->dclk);
  
 		for (i = 0; i < ztex->numNonces; i++) {
 			nonce = hdata[i].nonce;
@@ -330,11 +307,9 @@ static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 
 	}
 
-	ztex->errorRate[ztex->freqM] = ztex->errorCount[ztex->freqM] /	ztex->errorWeight[ztex->freqM] * (ztex->errorWeight[ztex->freqM] < 100? ztex->errorWeight[ztex->freqM] * 0.01: 1.0);
-	if (ztex->errorRate[ztex->freqM] > ztex->maxErrorRate[ztex->freqM])
-		ztex->maxErrorRate[ztex->freqM] = ztex->errorRate[ztex->freqM];
+	dclk_preUpdate(&ztex->dclk);
 
-	if (!ztex_updateFreq(ztex)) {
+	if (!ztex_updateFreq(thr)) {
 		// Something really serious happened, so mark this thread as dead!
 		free(lastnonce);
 		free(backlog);
@@ -372,7 +347,7 @@ get_ztex_api_extra_device_status(struct cgpu_info *ztex)
 	struct libztex_device *ztexr = ztex->device_ztex;
 
 	if (ztexr) {
-		double frequency = ztexr->freqM1 * (ztexr->freqM + 1);
+		double frequency = ztexr->freqM1 * (ztexr->dclk.freqM + 1);
 		root = api_add_freq(root, "Frequency", &frequency, true);
 	}
 
@@ -392,9 +367,9 @@ static bool ztex_prepare(struct thr_info *thr)
 	if (libztex_configureFpga(ztex) != 0)
 		return false;
 	ztex_releaseFpga(ztex);
-	ztex->freqM = ztex->freqMaxM+1;;
-	//ztex_updateFreq(ztex);
-	libztex_setFreq(ztex, ztex->freqMDefault);
+	ztex->dclk.freqM = ztex->dclk.freqMaxM+1;;
+	//ztex_updateFreq(thr);
+	libztex_setFreq(ztex, ztex->dclk.freqMDefault);
 	applog(LOG_DEBUG, "%s: prepare", ztex->repr);
 	return true;
 }

+ 78 - 0
dynclock.c

@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Luke Dashjr
+ * Copyright 2012 nelisky.btc@gmail.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "dynclock.h"
+#include "miner.h"
+
+void dclk_prepare(struct dclk_data *data)
+{
+	memset(data, 0, sizeof(*data));
+}
+
+bool dclk_updateFreq(struct dclk_data *data, dclk_change_clock_func_t changeclock, struct thr_info *thr)
+{
+	struct cgpu_info *cgpu = thr->cgpu;
+	int i, maxM, bestM;
+	double bestR, r;
+	bool rv = true;
+
+	for (i = 0; i < data->freqMaxM; i++)
+		if (data->maxErrorRate[i + 1] * i < data->maxErrorRate[i] * (i + 20))
+			data->maxErrorRate[i + 1] = data->maxErrorRate[i] * (1.0 + 20.0 / i);
+
+	maxM = 0;
+	while (maxM < data->freqMDefault && data->maxErrorRate[maxM + 1] < DCLK_MAXMAXERRORRATE)
+		maxM++;
+	while (maxM < data->freqMaxM && data->errorWeight[maxM] > 150 && data->maxErrorRate[maxM + 1] < DCLK_MAXMAXERRORRATE)
+		maxM++;
+
+	bestM = 0;
+	bestR = 0;
+	for (i = 0; i <= maxM; i++) {
+		r = (i + 1 + (i == data->freqM? DCLK_ERRORHYSTERESIS: 0)) * (1 - data->maxErrorRate[i]);
+		if (r > bestR) {
+			bestM = i;
+			bestR = r;
+		}
+	}
+
+	if (bestM != data->freqM) {
+		rv = changeclock(thr, bestM);
+	}
+
+	maxM = data->freqMDefault;
+	while (maxM < data->freqMaxM && data->errorWeight[maxM + 1] > 100)
+		maxM++;
+	if ((bestM < (1.0 - DCLK_OVERHEATTHRESHOLD) * maxM) && bestM < maxM - 1) {
+		applog(LOG_ERR, "%s %u: frequency drop of %.1f%% detect. This may be caused by overheating. FPGA is shut down to prevent damage.",
+		       cgpu->api->name, cgpu->device_id,
+		       (1.0 - 1.0 * bestM / maxM) * 100);
+		return false;
+	}
+	return rv;
+}
+
+void dclk_gotNonces(struct dclk_data *data)
+{
+	data->errorCount[data->freqM] *= 0.995;
+	data->errorWeight[data->freqM] = data->errorWeight[data->freqM] * 0.995 + 1.0;
+}
+
+void dclk_errorCount(struct dclk_data *data, double portion)
+{
+	data->errorCount[data->freqM] += portion;
+}
+
+void dclk_preUpdate(struct dclk_data *data)
+{
+	data->errorRate[data->freqM] = data->errorCount[data->freqM] / data->errorWeight[data->freqM] * (data->errorWeight[data->freqM] < 100 ? data->errorWeight[data->freqM] * 0.01 : 1.0);
+	if (data->errorRate[data->freqM] > data->maxErrorRate[data->freqM])
+		data->maxErrorRate[data->freqM] = data->errorRate[data->freqM];
+}

+ 32 - 0
dynclock.h

@@ -0,0 +1,32 @@
+#ifndef DYNCLOCK_H
+#define DYNCLOCK_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct thr_info;
+
+#define DCLK_MAXMAXERRORRATE 0.05
+#define DCLK_ERRORHYSTERESIS 0.1
+#define DCLK_OVERHEATTHRESHOLD 0.4
+
+struct dclk_data {
+	uint8_t freqM;
+	uint8_t freqMaxM;
+	uint8_t freqMDefault;
+
+	double errorCount[256];
+	double errorWeight[256];
+	double errorRate[256];
+	double maxErrorRate[256];
+};
+
+typedef bool (*dclk_change_clock_func_t)(struct thr_info *, int multiplier);
+
+extern void dclk_prepare(struct dclk_data *data);
+extern void dclk_gotNonces(struct dclk_data *);
+extern void dclk_errorCount(struct dclk_data *, double portion);
+extern void dclk_preUpdate(struct dclk_data *data);
+extern bool dclk_updateFreq(struct dclk_data *, dclk_change_clock_func_t changeclock, struct thr_info *);
+
+#endif

+ 17 - 18
libztex.c

@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#include "dynclock.h"
 #include "fpgautils.h"
 #include "miner.h"
 #include "libztex.h"
@@ -371,23 +372,27 @@ int libztex_selectFpga(struct libztex_device *ztex) {
 
 int libztex_setFreq(struct libztex_device *ztex, uint16_t freq) {
 	int cnt;
-	uint16_t oldfreq = ztex->freqM;
+	uint16_t oldfreq = ztex->dclk.freqM;
 
-	if (freq > ztex->freqMaxM)
-		freq = ztex->freqMaxM;
+	if (freq > ztex->dclk.freqMaxM)
+		freq = ztex->dclk.freqMaxM;
 
 	cnt = libusb_control_transfer(ztex->hndl, 0x40, 0x83, freq, 0, NULL, 0, 500);
 	if (unlikely(cnt < 0)) {
 		applog(LOG_ERR, "Ztex check device: Failed to set frequency with err %d", cnt);
 		return cnt;
 	}
-	ztex->freqM = freq;
-	if (oldfreq > ztex->freqMaxM) 
+	ztex->dclk.freqM = freq;
+	if (oldfreq > ztex->dclk.freqMaxM)
 		applog(LOG_WARNING, "%s: Frequency set to %0.2f Mhz",
-		       ztex->repr, ztex->freqM1 * (ztex->freqM + 1));
+		       ztex->repr,
+		       ztex->freqM1 * (ztex->dclk.freqM + 1)
+		);
 	else
 		applog(LOG_WARNING, "%s: Frequency change from %0.2f to %0.2f Mhz",
-		       ztex->repr, ztex->freqM1 * (oldfreq + 1), ztex->freqM1 * (ztex->freqM + 1));
+		       ztex->repr,
+		       ztex->freqM1 * (oldfreq + 1), ztex->freqM1 * (ztex->dclk.freqM + 1)
+		);
 
 	return 0;
 }
@@ -411,6 +416,7 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 	unsigned char buf[64];
 
 	newdev = malloc(sizeof(struct libztex_device));
+	dclk_prepare(&newdev->dclk);
 	newdev->bitFileName = NULL;
 	newdev->numberOfFpgas = -1;
 	newdev->valid = false;
@@ -510,15 +516,15 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 	newdev->numNonces = buf[1] + 1;
 	newdev->offsNonces = ((buf[2] & 255) | ((buf[3] & 255) << 8)) - 10000;
 	newdev->freqM1 = ((buf[4] & 255) | ((buf[5] & 255) << 8) ) * 0.01;
-	newdev->freqMaxM = (buf[7] & 255);
-	newdev->freqM = (buf[6] & 255);
-	newdev->freqMDefault = newdev->freqM;
+	newdev->dclk.freqMaxM = (buf[7] & 255);
+	newdev->dclk.freqM = (buf[6] & 255);
+	newdev->dclk.freqMDefault = newdev->dclk.freqM;
 	newdev->suspendSupported = (buf[0] == 5);
 	newdev->hashesPerClock = buf[0] > 2? (((buf[8] & 255) | ((buf[9] & 255) << 8)) + 1) / 128.0: 1.0;
 	newdev->extraSolutions = buf[0] > 4? buf[10]: 0;
 	
 	applog(LOG_DEBUG, "PID: %d numNonces: %d offsNonces: %d freqM1: %f freqMaxM: %d freqM: %d suspendSupported: %s hashesPerClock: %f extraSolutions: %d",
-	                 buf[0], newdev->numNonces, newdev->offsNonces, newdev->freqM1, newdev->freqMaxM, newdev->freqM, newdev->suspendSupported ? "T": "F", 
+	                 buf[0], newdev->numNonces, newdev->offsNonces, newdev->freqM1, newdev->dclk.freqMaxM, newdev->dclk.freqM, newdev->suspendSupported ? "T": "F",
 	                 newdev->hashesPerClock, newdev->extraSolutions);
 
 	if (buf[0] < 4) {
@@ -527,13 +533,6 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 		applog(LOG_WARNING, "HASHES_PER_CLOCK not defined, assuming %0.2f", newdev->hashesPerClock);
 	}
 
-	for (cnt=0; cnt < 255; cnt++) {
-		newdev->errorCount[cnt] = 0;
-		newdev->errorWeight[cnt] = 0;
-		newdev->errorRate[cnt] = 0;
-		newdev->maxErrorRate[cnt] = 0;
-	}
-
 	newdev->usbbus = libusb_get_bus_number(dev);
 	newdev->usbaddress = libusb_get_device_address(dev);
 	sprintf(newdev->repr, "ZTEX %s-1", newdev->snString);

+ 3 - 11
libztex.h

@@ -24,16 +24,14 @@
 
 #include <libusb-1.0/libusb.h>
 
+#include "dynclock.h"
+
 #define LIBZTEX_MAX_DESCRIPTORS 512
 #define LIBZTEX_SNSTRING_LEN 10
 
 #define LIBZTEX_IDVENDOR 0x221A
 #define LIBZTEX_IDPRODUCT 0x0100
 
-#define LIBZTEX_MAXMAXERRORRATE 0.05
-#define LIBZTEX_ERRORHYSTERESIS 0.1
-#define LIBZTEX_OVERHEATTHRESHOLD 0.4
-
 struct libztex_fpgastate {
 	bool fpgaConfigured;
 	unsigned char fpgaChecksum;
@@ -61,18 +59,12 @@ struct libztex_device {
 	uint8_t numNonces;
 	uint16_t offsNonces;
 	double freqM1;	
-	uint8_t freqM;
-	uint8_t freqMaxM;
-	uint8_t freqMDefault;
 	char* bitFileName;
 	bool suspendSupported;
 	double hashesPerClock;
 	uint8_t extraSolutions;
 
-	double errorCount[256];
-	double errorWeight[256];
-	double errorRate[256];
-	double maxErrorRate[256];
+	struct dclk_data dclk;
 
 	int numberOfFpgas;
 	int selectedFpga;