Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial multi-device OpenCL support for oclvanitygen and oclvanityminer.

  • Loading branch information...
commit af42e55a228c1bb7a81aa8cc7b2e971236eee110 1 parent 53903a7
samr7 authored
View
101 oclengine.c
@@ -50,6 +50,7 @@
#define round_up_pow2(x, a) (((x) + ((a)-1)) & ~((a)-1))
static void vg_ocl_free_args(vg_ocl_context_t *vocp);
+static void *vg_opencl_loop(vg_exec_context_t *arg);
/* OpenCL address searching mode */
@@ -872,6 +873,7 @@ vg_ocl_init(vg_context_t *vcp, vg_ocl_context_t *vocp, cl_device_id did,
memset(vocp, 0, sizeof(*vocp));
vg_exec_context_init(vcp, &vocp->base);
+ vocp->base.vxc_threadfunc = vg_opencl_loop;
pthread_mutex_init(&vocp->voc_lock, NULL);
pthread_cond_init(&vocp->voc_wait, NULL);
@@ -1872,8 +1874,8 @@ vg_opencl_thread(void *arg)
* Address search thread main loop
*/
-void *
-vg_opencl_loop(void *arg)
+static void *
+vg_opencl_loop(vg_exec_context_t *arg)
{
vg_ocl_context_t *vocp = (vg_ocl_context_t *) arg;
int i;
@@ -2397,7 +2399,7 @@ get_platform(int num)
}
void
-enumerate_opencl(void)
+vg_ocl_enumerate_devices(void)
{
cl_platform_id *pids;
cl_device_id *dids;
@@ -2420,7 +2422,7 @@ enumerate_opencl(void)
}
}
-cl_device_id
+static cl_device_id
get_opencl_device(int platformidx, int deviceidx)
{
cl_platform_id pid;
@@ -2432,7 +2434,6 @@ get_opencl_device(int platformidx, int deviceidx)
if (did)
return did;
}
- enumerate_opencl();
return NULL;
}
@@ -2603,6 +2604,96 @@ vg_ocl_context_new(vg_context_t *vcp,
return NULL;
}
+vg_ocl_context_t *
+vg_ocl_context_new_from_devstr(vg_context_t *vcp, const char *devstr,
+ int safemode, int verify)
+{
+ int platformidx, deviceidx;
+ int worksize = 0, nthreads = 0, nrows = 0, ncols = 0, invsize = 0;
+
+ char *dsd, *part, *part2, *save, *param;
+
+ dsd = strdup(devstr);
+ if (!dsd)
+ return NULL;
+
+ save = NULL;
+ part = strtok_r(dsd, ",", &save);
+
+ part2 = strchr(part, ':');
+ if (!part2) {
+ fprintf(stderr, "Invalid device specifier '%s'\n", part);
+ free(dsd);
+ return NULL;
+ }
+
+ *part2 = '\0';
+ platformidx = atoi(part);
+ deviceidx = atoi(part2 + 1);
+
+ while ((part = strtok_r(NULL, ",", &save)) != NULL) {
+ param = strchr(part, '=');
+ if (!param) {
+ fprintf(stderr, "Unrecognized parameter '%s'\n", part);
+ continue;
+ }
+
+ *param = '\0';
+ param++;
+
+ if (!strcmp(part, "grid")) {
+ ncols = strtol(param, &part2, 0);
+ if (part2 && *part2 == 'x') {
+ nrows = strtol(part2+1, NULL, 0);
+ }
+ if (!nrows || !ncols) {
+ fprintf(stderr,
+ "Invalid grid size '%s'\n", param);
+ nrows = 0;
+ ncols = 0;
+ continue;
+ }
+ }
+
+ else if (!strcmp(part, "invsize")) {
+ invsize = atoi(param);
+ if (!invsize) {
+ fprintf(stderr,
+ "Invalid modular inverse size '%s'\n",
+ param);
+ continue;
+ }
+ if (invsize & (invsize - 1)) {
+ fprintf(stderr,
+ "Modular inverse size %d must be "
+ "a power of 2\n", invsize);
+ invsize = 0;
+ continue;
+ }
+ }
+
+ else if (!strcmp(part, "threads")) {
+ nthreads = atoi(param);
+ if (nthreads == 0) {
+ fprintf(stderr,
+ "Invalid thread count '%s'\n", optarg);
+ continue;
+ }
+ }
+
+ else {
+ fprintf(stderr, "Unrecognized parameter '%s'\n", part);
+ }
+ }
+
+ free(dsd);
+
+ return vg_ocl_context_new(vcp, platformidx, deviceidx, safemode,
+ verify, worksize, nthreads, nrows, ncols,
+ invsize);
+}
+
+
void
vg_ocl_context_free(vg_ocl_context_t *vocp)
{
View
6 oclengine.h
@@ -30,6 +30,10 @@ extern vg_ocl_context_t *vg_ocl_context_new(
int invsize);
extern void vg_ocl_context_free(vg_ocl_context_t *vocp);
-extern void *vg_opencl_loop(void *vocp);
+extern vg_ocl_context_t *vg_ocl_context_new_from_devstr(
+ vg_context_t *vcp, const char *devstr, int safemode, int verify)
+;
+
+extern void vg_ocl_enumerate_devices(void);
#endif /* !defined (__VG_OCLENGINE_H__) */
View
58 oclvanitygen.c
@@ -45,6 +45,11 @@ usage(const char *name)
"location or imported into a bitcoin client to spend any balance received on\n"
"the address.\n"
"By default, <pattern> is interpreted as an exact prefix.\n"
+"By default, if no device is specified, and the system has exactly one OpenCL\n"
+"device, it will be selected automatically, otherwise if the system has\n"
+"multiple OpenCL devices and no device is specified, an error will be\n"
+"reported. To use multiple devices simultaneously, specify the -D option for\n"
+"each device.\n"
"\n"
"Options:\n"
"-v Verbose output\n"
@@ -58,6 +63,9 @@ usage(const char *name)
"-E <password> Encrypt private keys with <password> (UNSAFE)\n"
"-p <platform> Select OpenCL platform\n"
"-d <device> Select OpenCL device\n"
+"-D <devstr> Use OpenCL device, identified by device string\n"
+" Form: <platform>:<devicenumber>[,<options>]\n"
+" Example: 0:0,grid=1024x1024\n"
"-S Safe mode, disable OpenCL loop unrolling optimizations\n"
"-w <worksize> Set work items per thread in a work unit\n"
"-t <threads> Set target thread count per multiprocessor\n"
@@ -71,6 +79,8 @@ usage(const char *name)
version, name);
}
+#define MAX_DEVS 32
+
int
main(int argc, char **argv)
{
@@ -99,9 +109,12 @@ main(int argc, char **argv)
EC_POINT *pubkey_base = NULL;
const char *result_file = NULL;
const char *key_password = NULL;
+ char *devstrs[MAX_DEVS];
+ int ndevstrs = 0;
+ int opened = 0;
while ((opt = getopt(argc, argv,
- "vqikNTX:eE:p:P:d:w:t:g:b:VSh?f:o:s:")) != -1) {
+ "vqikNTX:eE:p:P:d:w:t:g:b:VSh?f:o:s:D:")) != -1) {
switch (opt) {
case 'v':
verbose = 2;
@@ -188,6 +201,15 @@ main(int argc, char **argv)
case 'S':
safe_mode = 1;
break;
+ case 'D':
+ if (ndevstrs >= MAX_DEVS) {
+ fprintf(stderr,
+ "Too many OpenCL devices (limit %d)\n",
+ MAX_DEVS);
+ return 1;
+ }
+ devstrs[ndevstrs++] = optarg;
+ break;
case 'P': {
if (pubkey_base != NULL) {
fprintf(stderr,
@@ -338,14 +360,38 @@ main(int argc, char **argv)
fprintf(stderr,
"Regular expressions: %ld\n", vcp->vc_npatterns);
- vocp = vg_ocl_context_new(vcp, platformidx, deviceidx,
- safe_mode, verify_mode,
- worksize, nthreads, nrows, ncols, invsize);
- if (!vocp) {
+ if (ndevstrs) {
+ for (opt = 0; opt < ndevstrs; opt++) {
+ vocp = vg_ocl_context_new_from_devstr(vcp, devstrs[opt],
+ safe_mode,
+ verify_mode);
+ if (!vocp) {
+ fprintf(stderr,
+ "Could not open device '%s', ignoring\n",
+ devstrs[opt]);
+ } else {
+ opened++;
+ }
+ }
+ } else {
+ vocp = vg_ocl_context_new(vcp, platformidx, deviceidx,
+ safe_mode, verify_mode,
+ worksize, nthreads,
+ nrows, ncols, invsize);
+ if (vocp)
+ opened++;
+ }
+
+ if (!opened) {
+ vg_ocl_enumerate_devices();
return 1;
}
- vg_opencl_loop(vocp);
+ opt = vg_context_start_threads(vcp);
+ if (opt)
+ return 1;
+
+ vg_context_wait_for_completion(vcp);
vg_ocl_context_free(vocp);
return 0;
}
View
72 oclvanityminer.c
@@ -735,6 +735,11 @@ usage(const char *name)
"generate the address with the best difficulty to reward ratio. Maintains\n"
"contact with the bounty pool server and periodically refreshes the bounty\n"
"list.\n"
+"By default, if no device is specified, and the system has exactly one OpenCL\n"
+"device, it will be selected automatically, otherwise if the system has\n"
+"multiple OpenCL devices and no device is specified, an error will be\n"
+"reported. To use multiple devices simultaneously, specify the -D option for\n"
+"each device.\n"
"\n"
"Options:\n"
"-u <URL> Bounty pool URL\n"
@@ -744,6 +749,9 @@ usage(const char *name)
"-q Quiet output\n"
"-p <platform> Select OpenCL platform\n"
"-d <device> Select OpenCL device\n"
+"-D <devstr> Use OpenCL device, identified by device string\n"
+" Form: <platform>:<devicenumber>[,<options>]\n"
+" Example: 0:0,grid=1024x1024\n"
"-S Safe mode, disable OpenCL loop unrolling optimizations\n"
"-w <worksize> Set work items per thread in a work unit\n"
"-t <threads> Set target thread count per multiprocessor\n"
@@ -753,6 +761,7 @@ usage(const char *name)
version, name);
}
+#define MAX_DEVS 32
int
main(int argc, char **argv)
@@ -770,12 +779,15 @@ main(int argc, char **argv)
int invsize = 0;
int verify_mode = 0;
int safe_mode = 0;
+
+ char *devstrs[MAX_DEVS];
+ int ndevstrs = 0;
+
vg_context_t *vcp = NULL;
vg_ocl_context_t *vocp = NULL;
int res;
int thread_started = 0;
- pthread_t thread;
pubkeybatch_t *active_pkb = NULL;
server_context_t *scp = NULL;
@@ -794,7 +806,7 @@ main(int argc, char **argv)
}
while ((opt = getopt(argc, argv,
- "u:a:vqp:d:w:t:g:b:VSh?i:")) != -1) {
+ "u:a:vqp:d:w:t:g:b:VD:Sh?i:")) != -1) {
switch (opt) {
case 'u':
url = optarg;
@@ -871,6 +883,15 @@ main(int argc, char **argv)
case 'S':
safe_mode = 1;
break;
+ case 'D':
+ if (ndevstrs >= MAX_DEVS) {
+ fprintf(stderr,
+ "Too many OpenCL devices (limit %d)\n",
+ MAX_DEVS);
+ return 1;
+ }
+ devstrs[ndevstrs++] = optarg;
+ break;
default:
usage(argv[0]);
return 1;
@@ -915,6 +936,34 @@ main(int argc, char **argv)
if (server_context_getwork(scp))
return 1;
+ /* Set up OpenCL */
+ res = 0;
+ if (ndevstrs) {
+ for (opt = 0; opt < ndevstrs; opt++) {
+ vocp = vg_ocl_context_new_from_devstr(vcp, devstrs[opt],
+ safe_mode,
+ verify_mode);
+ if (!vocp) {
+ fprintf(stderr,
+ "Could not open device '%s', ignoring\n",
+ devstrs[opt]);
+ } else {
+ res++;
+ }
+ }
+ } else {
+ vocp = vg_ocl_context_new(vcp, platformidx, deviceidx,
+ safe_mode, verify_mode,
+ worksize, nthreads,
+ nrows, ncols, invsize);
+ if (vocp)
+ res++;
+ }
+ if (!res) {
+ vg_ocl_enumerate_devices();
+ return 1;
+ }
+
while (1) {
if (avl_root_empty(&scp->items))
server_context_getwork(scp);
@@ -929,10 +978,8 @@ main(int argc, char **argv)
if (thread_started && (!active_pkb || (pkb != active_pkb))) {
/* If a thread is running, stop it */
- vcp->vc_halt = 1;
- pthread_join(thread, NULL);
+ vg_context_stop_threads(vcp);
thread_started = 0;
- vcp->vc_halt = 0;
if (active_pkb) {
check_solution(scp, active_pkb);
active_pkb = NULL;
@@ -970,18 +1017,9 @@ main(int argc, char **argv)
assert(vcp->vc_npatterns);
}
- if (!vocp) {
- vocp = vg_ocl_context_new(vcp,
- platformidx, deviceidx,
- safe_mode, verify_mode,
- worksize, nthreads, nrows,
- ncols, invsize);
- if (!vocp)
- return 1;
- }
-
- res = pthread_create(&thread, NULL,
- vg_opencl_loop, vocp);
+ res = vg_context_start_threads(vcp);
+ if (res)
+ return 1;
thread_started = 1;
active_pkb = pkb;
}
View
70 pattern.c
@@ -54,16 +54,14 @@ static pthread_mutex_t vg_thread_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t vg_thread_rdcond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t vg_thread_wrcond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t vg_thread_upcond = PTHREAD_COND_INITIALIZER;
-static vg_exec_context_t *vg_threads = NULL;
-static int vg_thread_excl = 0;
static void
__vg_exec_context_yield(vg_exec_context_t *vxcp)
{
vxcp->vxc_lockmode = 0;
- while (vg_thread_excl) {
+ while (vxcp->vxc_vc->vc_thread_excl) {
if (vxcp->vxc_stop) {
- assert(vg_thread_excl);
+ assert(vxcp->vxc_vc->vc_thread_excl);
vxcp->vxc_stop = 0;
pthread_cond_signal(&vg_thread_upcond);
}
@@ -78,6 +76,7 @@ int
vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp)
{
vg_exec_context_t *tp;
+ vg_context_t *vcp;
if (vxcp->vxc_lockmode == 2)
return 0;
@@ -86,20 +85,21 @@ vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp)
assert(vxcp->vxc_lockmode == 1);
vxcp->vxc_lockmode = 0;
+ vcp = vxcp->vxc_vc;
- if (vg_thread_excl++) {
+ if (vcp->vc_thread_excl++) {
assert(vxcp->vxc_stop);
vxcp->vxc_stop = 0;
pthread_cond_signal(&vg_thread_upcond);
pthread_cond_wait(&vg_thread_wrcond, &vg_thread_lock);
- for (tp = vg_threads; tp != NULL; tp = tp->vxc_next) {
+ for (tp = vcp->vc_threads; tp != NULL; tp = tp->vxc_next) {
assert(!tp->vxc_lockmode);
assert(!tp->vxc_stop);
}
} else {
- for (tp = vg_threads; tp != NULL; tp = tp->vxc_next) {
+ for (tp = vcp->vc_threads; tp != NULL; tp = tp->vxc_next) {
if (tp->vxc_lockmode) {
assert(tp->vxc_lockmode != 2);
tp->vxc_stop = 1;
@@ -107,7 +107,9 @@ vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp)
}
do {
- for (tp = vg_threads; tp != NULL; tp = tp->vxc_next) {
+ for (tp = vcp->vc_threads;
+ tp != NULL;
+ tp = tp->vxc_next) {
if (tp->vxc_lockmode) {
assert(tp->vxc_lockmode != 2);
pthread_cond_wait(&vg_thread_upcond,
@@ -127,10 +129,9 @@ void
vg_exec_context_downgrade_lock(vg_exec_context_t *vxcp)
{
pthread_mutex_lock(&vg_thread_lock);
-
assert(vxcp->vxc_lockmode == 2);
assert(!vxcp->vxc_stop);
- if (!--vg_thread_excl) {
+ if (!--vxcp->vxc_vc->vc_thread_excl) {
vxcp->vxc_lockmode = 1;
pthread_cond_broadcast(&vg_thread_rdcond);
pthread_mutex_unlock(&vg_thread_lock);
@@ -166,8 +167,8 @@ vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp)
vxcp->vxc_lockmode = 0;
vxcp->vxc_stop = 0;
- vxcp->vxc_next = vg_threads;
- vg_threads = vxcp;
+ vxcp->vxc_next = vcp->vc_threads;
+ vcp->vc_threads = vxcp;
__vg_exec_context_yield(vxcp);
pthread_mutex_unlock(&vg_thread_lock);
return 1;
@@ -185,7 +186,7 @@ vg_exec_context_del(vg_exec_context_t *vxcp)
assert(vxcp->vxc_lockmode == 1);
vxcp->vxc_lockmode = 0;
- for (pprev = &vg_threads, tp = *pprev;
+ for (pprev = &vxcp->vxc_vc->vc_threads, tp = *pprev;
(tp != vxcp) && (tp != NULL);
pprev = &tp->vxc_next, tp = *pprev);
@@ -634,6 +635,49 @@ vg_context_hash160_sort(vg_context_t *vcp, void *buf)
return vcp->vc_hash160_sort(vcp, buf);
}
+int
+vg_context_start_threads(vg_context_t *vcp)
+{
+ vg_exec_context_t *vxcp;
+ int res;
+
+ for (vxcp = vcp->vc_threads; vxcp != NULL; vxcp = vxcp->vxc_next) {
+ res = pthread_create((pthread_t *) &vxcp->vxc_pthread,
+ NULL,
+ (void *(*)(void *)) vxcp->vxc_threadfunc,
+ vxcp);
+ if (res) {
+ fprintf(stderr, "ERROR: could not create thread: %d\n",
+ res);
+ vg_context_stop_threads(vcp);
+ return -1;
+ }
+ vxcp->vxc_thread_active = 1;
+ }
+ return 0;
+}
+
+void
+vg_context_stop_threads(vg_context_t *vcp)
+{
+ vcp->vc_halt = 1;
+ vg_context_wait_for_completion(vcp);
+ vcp->vc_halt = 0;
+}
+
+void
+vg_context_wait_for_completion(vg_context_t *vcp)
+{
+ vg_exec_context_t *vxcp;
+
+ for (vxcp = vcp->vc_threads; vxcp != NULL; vxcp = vxcp->vxc_next) {
+ if (!vxcp->vxc_thread_active)
+ continue;
+ pthread_join((pthread_t) vxcp->vxc_pthread, NULL);
+ vxcp->vxc_thread_active = 0;
+ }
+}
+
/*
* Find the bignum ranges that produce a given prefix.
View
61 pattern.h
@@ -22,6 +22,8 @@
#include <openssl/bn.h>
#include <openssl/ec.h>
+#include <pthread.h>
+
#ifdef _WIN32
#include "winglue.h"
#else
@@ -35,11 +37,15 @@
#define VANITYGEN_VERSION "0.20pre"
-
typedef struct _vg_context_s vg_context_t;
+struct _vg_exec_context_s;
+typedef struct _vg_exec_context_s vg_exec_context_t;
+
+typedef void *(*vg_exec_context_threadfunc_t)(vg_exec_context_t *);
+
/* Context of one pattern-matching unit within the process */
-typedef struct _vg_exec_context_s {
+struct _vg_exec_context_s {
vg_context_t *vxc_vc;
BN_CTX *vxc_bnctx;
EC_KEY *vxc_key;
@@ -50,23 +56,15 @@ typedef struct _vg_exec_context_s {
BIGNUM vxc_bntmp;
BIGNUM vxc_bntmp2;
+ vg_exec_context_threadfunc_t vxc_threadfunc;
+ pthread_t vxc_pthread;
+ int vxc_thread_active;
+
/* Thread synchronization */
struct _vg_exec_context_s *vxc_next;
int vxc_lockmode;
int vxc_stop;
-} vg_exec_context_t;
-
-/* Init/cleanup for common execution context */
-extern int vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp);
-extern void vg_exec_context_del(vg_exec_context_t *vxcp);
-extern void vg_exec_context_consolidate_key(vg_exec_context_t *vxcp);
-extern void vg_exec_context_calc_address(vg_exec_context_t *vxcp);
-extern EC_KEY *vg_exec_context_new_key(void);
-
-/* Execution context lock handling functions */
-extern void vg_exec_context_downgrade_lock(vg_exec_context_t *vxcp);
-extern int vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp);
-extern void vg_exec_context_yield(vg_exec_context_t *vxcp);
+};
typedef void (*vg_free_func_t)(vg_context_t *);
@@ -106,6 +104,9 @@ struct _vg_context_s {
EC_POINT *vc_pubkey_base;
int vc_halt;
+ vg_exec_context_t *vc_threads;
+ int vc_thread_excl;
+
/* Internal methods */
vg_free_func_t vc_free;
vg_add_pattern_func_t vc_add_patterns;
@@ -126,26 +127,48 @@ struct _vg_context_s {
};
+/* Base context methods */
extern void vg_context_free(vg_context_t *vcp);
extern int vg_context_add_patterns(vg_context_t *vcp,
const char ** const patterns, int npatterns);
extern void vg_context_clear_all_patterns(vg_context_t *vcp);
-extern int vg_context_hash160_sort(vg_context_t *vcp, void *buf);
-extern void vg_context_thread_exit(vg_context_t *vcp);
-
+extern int vg_context_start_threads(vg_context_t *vcp);
+extern void vg_context_stop_threads(vg_context_t *vcp);
+extern void vg_context_wait_for_completion(vg_context_t *vcp);
+/* Prefix context methods */
extern vg_context_t *vg_prefix_context_new(int addrtype, int privtype,
int caseinsensitive);
extern double vg_prefix_get_difficulty(int addrtype, const char *pattern);
+/* Regex context methods */
extern vg_context_t *vg_regex_context_new(int addrtype, int privtype);
+/* Utility functions */
extern int vg_output_timing(vg_context_t *vcp, int cycle, struct timeval *last);
-
extern void vg_output_match_console(vg_context_t *vcp, EC_KEY *pkey,
const char *pattern);
extern void vg_output_timing_console(vg_context_t *vcp, double count,
unsigned long long rate,
unsigned long long total);
+
+
+/* Internal vg_context methods */
+extern int vg_context_hash160_sort(vg_context_t *vcp, void *buf);
+extern void vg_context_thread_exit(vg_context_t *vcp);
+
+/* Internal Init/cleanup for common execution context */
+extern int vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp);
+extern void vg_exec_context_del(vg_exec_context_t *vxcp);
+extern void vg_exec_context_consolidate_key(vg_exec_context_t *vxcp);
+extern void vg_exec_context_calc_address(vg_exec_context_t *vxcp);
+extern EC_KEY *vg_exec_context_new_key(void);
+
+/* Internal execution context lock handling functions */
+extern void vg_exec_context_downgrade_lock(vg_exec_context_t *vxcp);
+extern int vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp);
+extern void vg_exec_context_yield(vg_exec_context_t *vxcp);
+
+
#endif /* !defined (__VG_PATTERN_H__) */
Please sign in to comment.
Something went wrong with that request. Please try again.