Add command line parsing, and multiple threads.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
diff --git a/Makefile b/Makefile
index ac4519e..81a2076 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-CFLAGS= -O2 -Wall -g
+CFLAGS= -O2 -Wall -g -march=native -pthread
PROG = minerd
diff --git a/cpu-miner.c b/cpu-miner.c
index 9b6e9f7..81363dc 100644
--- a/cpu-miner.c
+++ b/cpu-miner.c
@@ -10,20 +10,47 @@
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
-#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <argp.h>
#include <jansson.h>
#include <curl/curl.h>
#include <openssl/bn.h>
+#define PROGRAM_NAME "minerd"
+
#include "sha256_generic.c"
enum {
- POW_SLEEP_INTERVAL = 5,
+ STAT_SLEEP_INTERVAL = 10,
+ POW_SLEEP_INTERVAL = 1,
};
-static const bool opt_verbose = false;
-static const bool opt_debug = false;
+static bool opt_verbose;
+static bool opt_debug;
+static bool program_running = true;
static const bool opt_time = true;
+static int opt_n_threads = 1;
+static pthread_mutex_t stats_mutex = PTHREAD_MUTEX_INITIALIZER;
+static uint64_t hash_ctr;
+
+static struct argp_option options[] = {
+ { "threads", 't', "N", 0,
+ "Number of miner threads" },
+ { "debug", 'D', NULL, 0,
+ "Enable debug output" },
+ { "verbose", 'v', NULL, 0,
+ "Enable verbose output" },
+ { }
+};
+
+static const char doc[] =
+PROGRAM_NAME " - CPU miner for bitcoin";
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+static const struct argp argp = { options, parse_opt, NULL, doc };
struct data_buffer {
void *buf;
@@ -289,6 +316,15 @@ err_out:
return NULL;
}
+static void inc_stats(uint64_t n_hashes)
+{
+ pthread_mutex_lock(&stats_mutex);
+
+ hash_ctr += n_hashes;
+
+ pthread_mutex_unlock(&stats_mutex);
+}
+
#define ___constant_swab32(x) ((u32)( \
(((u32)(x) & (u32)0x000000ffUL) << 24) | \
(((u32)(x) & (u32)0x0000ff00UL) << 8) | \
@@ -318,9 +354,6 @@ static uint32_t scanhash(unsigned char *midstate, unsigned char *data,
uint32_t *hash32 = (uint32_t *) hash;
uint32_t *nonce = (uint32_t *)(data + 12);
uint32_t n;
- time_t t_start;
-
- t_start = time(NULL);
while (1) {
n = *nonce;
@@ -344,15 +377,10 @@ static uint32_t scanhash(unsigned char *midstate, unsigned char *data,
}
if ((n & 0xffffff) == 0) {
- time_t t_end = time(NULL);
- time_t diff = t_end - t_start;
- long double nd = n;
- long double sd = diff;
- if (opt_time) {
- fprintf(stderr,
- "DBG: end of nonce range, %.2Lf khps\n",
- (nd / sd) / 1000.0);
- }
+ inc_stats(n);
+
+ if (opt_debug)
+ fprintf(stderr, "DBG: end of nonce range\n");
return 0;
}
}
@@ -415,7 +443,7 @@ out:
free(hexstr);
}
-static int main_loop(void)
+static void *miner_thread(void *dummy)
{
static const char *rpc_req =
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
@@ -429,7 +457,7 @@ static int main_loop(void)
val = json_rpc_call(url, userpass, rpc_req);
if (!val) {
fprintf(stderr, "json_rpc_call failed\n");
- return 1;
+ return NULL;
}
if (opt_verbose) {
@@ -442,7 +470,7 @@ static int main_loop(void)
work = work_decode(json_object_get(val, "result"));
if (!work) {
fprintf(stderr, "work decode failed\n");
- return 1;
+ return NULL;
}
json_decref(val);
@@ -463,11 +491,91 @@ static int main_loop(void)
work_free(work);
}
+ return NULL;
+}
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+ int v;
+
+ switch(key) {
+ case 'v':
+ opt_verbose = true;
+ break;
+ case 'D':
+ opt_debug = true;
+ break;
+ case 't':
+ v = atoi(arg);
+ if (v < 1 || v > 9999) /* sanity check */
+ argp_usage(state);
+
+ opt_n_threads = v;
+ break;
+ case ARGP_KEY_ARG:
+ argp_usage(state); /* too many args */
+ break;
+ case ARGP_KEY_END:
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
return 0;
}
+static void calc_stats(void)
+{
+ uint64_t hashes;
+ long double hd, sd;
+
+ pthread_mutex_lock(&stats_mutex);
+
+ hashes = hash_ctr;
+ hash_ctr = 0;
+
+ pthread_mutex_unlock(&stats_mutex);
+
+ hashes = hashes / 1000;
+
+ hd = hashes;
+ sd = STAT_SLEEP_INTERVAL;
+
+ fprintf(stderr, "wildly inaccurate HashMeter: %.2Lf khash/sec\n", hd / sd);
+}
+
int main (int argc, char *argv[])
{
- return main_loop();
+ error_t aprc;
+ int i;
+
+ aprc = argp_parse(&argp, argc, argv, 0, NULL, NULL);
+ if (aprc) {
+ fprintf(stderr, "argp_parse failed: %s\n", strerror(aprc));
+ return 1;
+ }
+
+ if (setpriority(PRIO_PROCESS, 0, 19))
+ perror("setpriority");
+
+ for (i = 0; i < opt_n_threads; i++) {
+ pthread_t t;
+
+ if (pthread_create(&t, NULL, miner_thread, NULL)) {
+ fprintf(stderr, "thread %d create failed\n", i);
+ return 1;
+ }
+
+ sleep(1); /* don't pound server all at once */
+ }
+
+ fprintf(stderr, "%d miner threads started.\n", opt_n_threads);
+
+ while (program_running) {
+ sleep(STAT_SLEEP_INTERVAL);
+ calc_stats();
+ }
+
+ return 0;
}