diff --git a/api.c b/api.c index 77ab5c2498..fe081d5ad3 100644 --- a/api.c +++ b/api.c @@ -163,6 +163,7 @@ static const char *SICK = "Sick"; static const char *NOSTART = "NoStart"; static const char *DISABLED = "Disabled"; static const char *ALIVE = "Alive"; +static const char *UNKNOWN = "Unknown"; #define _DYNAMIC "D" static const char *DYNAMIC = _DYNAMIC; @@ -770,156 +771,126 @@ static void minerconfig(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, strcat(io_buffer, buf); } -static void gpustatus(int gpu, bool isjson) +static const char* +bool2str(bool b) { - char intensity[20]; - char buf[BUFSIZ]; - char *enabled; - char *status; - float gt, gv; - int ga, gf, gp, gc, gm, pt; - - if (gpu >= 0 && gpu < nDevs) { - struct cgpu_info *cgpu = &gpus[gpu]; - - cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60; - -#ifdef HAVE_ADL - if (!gpu_stats(gpu, >, &gc, &gm, &gv, &ga, &gf, &gp, &pt)) -#endif - gt = gv = gm = gc = ga = gf = gp = pt = 0; - - if (cgpu->deven != DEV_DISABLED) - enabled = (char *)YES; - else - enabled = (char *)NO; - - if (cgpu->status == LIFE_DEAD) - status = (char *)DEAD; - else if (cgpu->status == LIFE_SICK) - status = (char *)SICK; - else if (cgpu->status == LIFE_NOSTART) - status = (char *)NOSTART; - else - status = (char *)ALIVE; - - if (cgpu->dynamic) - strcpy(intensity, DYNAMIC); - else - sprintf(intensity, "%d", cgpu->intensity); - - if (isjson) - sprintf(buf, "{\"GPU\":%d,\"Enabled\":\"%s\",\"Status\":\"%s\",\"Temperature\":%.2f,\"Fan Speed\":%d,\"Fan Percent\":%d,\"GPU Clock\":%d,\"Memory Clock\":%d,\"GPU Voltage\":%.3f,\"GPU Activity\":%d,\"Powertune\":%d,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Intensity\":\"%s\",\"Last Share Pool\":%d,\"Last Share Time\":%lu,\"Total MH\":%.4f}", - gpu, enabled, status, gt, gf, gp, gc, gm, gv, ga, pt, - cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling, - cgpu->accepted, cgpu->rejected, cgpu->hw_errors, - cgpu->utility, intensity, - ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, - (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes); - else - sprintf(buf, "GPU=%d,Enabled=%s,Status=%s,Temperature=%.2f,Fan Speed=%d,Fan Percent=%d,GPU Clock=%d,Memory Clock=%d,GPU Voltage=%.3f,GPU Activity=%d,Powertune=%d,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Intensity=%s,Last Share Pool=%d,Last Share Time=%lu,Total MH=%.4f%c", - gpu, enabled, status, gt, gf, gp, gc, gm, gv, ga, pt, - cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling, - cgpu->accepted, cgpu->rejected, cgpu->hw_errors, - cgpu->utility, intensity, - ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, - (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes, SEPARATOR); + return b ? YES : NO; +} - strcat(io_buffer, buf); +static const char* +status2str(enum alive status) +{ + switch (status) { + case LIFE_WELL: + return ALIVE; + case LIFE_SICK: + return SICK; + case LIFE_DEAD: + return DEAD; + case LIFE_NOSTART: + return NOSTART; + default: + return UNKNOWN; } } -#if defined(USE_BITFORCE) || defined(USE_ICARUS) -static void pgastatus(int pga, bool isjson) +static void +append_kv(char *buf, json_t*info, bool isjson) { - char buf[BUFSIZ]; - char *enabled; - char *status; - int numpga = numpgas(); - - if (numpga > 0 && pga >= 0 && pga < numpga) { - int dev = pgadevice(pga); - if (dev < 0) // Should never happen - return; - - struct cgpu_info *cgpu = devices[dev]; + json_t *value; + const char *key, *tmpl = isjson ? ",\"%s\":%s" : ",%s=%s"; + char *vdump; - cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60; - - if (cgpu->deven != DEV_DISABLED) - enabled = (char *)YES; - else - enabled = (char *)NO; - - if (cgpu->status == LIFE_DEAD) - status = (char *)DEAD; - else if (cgpu->status == LIFE_SICK) - status = (char *)SICK; - else if (cgpu->status == LIFE_NOSTART) - status = (char *)NOSTART; - else - status = (char *)ALIVE; - - if (isjson) - sprintf(buf, "{\"PGA\":%d,\"Name\":\"%s\",\"ID\":%d,\"Enabled\":\"%s\",\"Status\":\"%s\",\"Temperature\":%.2f,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Last Share Pool\":%d,\"Last Share Time\":%lu,\"Total MH\":%.4f}", - pga, cgpu->api->name, cgpu->device_id, - enabled, status, cgpu->temp, - cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling, - cgpu->accepted, cgpu->rejected, cgpu->hw_errors, cgpu->utility, - ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, - (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes); + json_object_foreach(info, key, value) { + if (isjson || !json_is_string(value)) + vdump = json_dumps(value, JSON_COMPACT | JSON_ENCODE_ANY); else - sprintf(buf, "PGA=%d,Name=%s,ID=%d,Enabled=%s,Status=%s,Temperature=%.2f,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Last Share Pool=%d,Last Share Time=%lu,Total MH=%.4f%c", - pga, cgpu->api->name, cgpu->device_id, - enabled, status, cgpu->temp, - cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling, - cgpu->accepted, cgpu->rejected, cgpu->hw_errors, cgpu->utility, - ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, - (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes, SEPARATOR); - - strcat(io_buffer, buf); + vdump = strdup(json_string_value(value)); + tailsprintf(buf, tmpl, key, vdump); + free(vdump); } } -#endif -#ifdef WANT_CPUMINE -static void cpustatus(int cpu, bool isjson) +static void +devdetail_an(char *buf, struct cgpu_info *cgpu, bool isjson) { - char buf[BUFSIZ]; + tailsprintf(buf, isjson + ? "{\"%s\":%d,Driver=%s" + : "%s=%d,Driver=%s", + cgpu->api->name, cgpu->device_id, + cgpu->api->dname + ); + + if (cgpu->kname) + tailsprintf(buf, isjson ? ",\"Kernel\":\"%s\"" : ",Kernel=%s", cgpu->kname); + if (cgpu->name) + tailsprintf(buf, isjson ? ",\"Model\":\"%s\"" : ",Model=%s", cgpu->name); + if (cgpu->device_path) + tailsprintf(buf, isjson ? ",\"Device Path\":\"%s\"" : ",Device Path=%s", cgpu->device_path); + + if (cgpu->api->get_extra_device_detail) { + json_t *info = cgpu->api->get_extra_device_detail(cgpu); + append_kv(buf, info, isjson); + json_decref(info); + } + + tailsprintf(buf, "%c", isjson ? '}' : SEPARATOR); +} - if (opt_n_threads > 0 && cpu >= 0 && cpu < num_processors) { - struct cgpu_info *cgpu = &cpus[cpu]; +static void devstatus_an(char *buf, struct cgpu_info *cgpu, bool isjson) +{ + tailsprintf(buf, isjson + ? "{\"%s\":%d,\"Enabled\":\"%s\",\"Status\":\"%s\",\"Temperature\":%.2f,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Hardware Errors\":%d,\"Utility\":%.2f,\"Last Share Pool\":%d,\"Last Share Time\":%lu,\"Total MH\":%.4f" + : "%s=%d,Enabled=%s,Status=%s,Temperature=%.2f,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Hardware Errors=%d,Utility=%.2f,Last Share Pool=%d,Last Share Time=%lu,Total MH=%.4f", + cgpu->api->name, cgpu->device_id, + bool2str(cgpu->deven != DEV_DISABLED), + status2str(cgpu->status), + cgpu->temp, + cgpu->total_mhashes / total_secs, opt_log_interval, cgpu->rolling, + cgpu->accepted, cgpu->rejected, cgpu->hw_errors, + cgpu->utility, + ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, + (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes + ); + + if (cgpu->api->get_extra_device_status) { + json_t *info = cgpu->api->get_extra_device_status(cgpu); + append_kv(buf, info, isjson); + json_decref(info); + } + + tailsprintf(buf, "%c", isjson ? '}' : SEPARATOR); +} - cgpu->utility = cgpu->accepted / ( total_secs ? total_secs : 1 ) * 60; +static void gpustatus(int gpu, bool isjson) +{ + if (gpu < 0 || gpu >= nDevs) + return; + devstatus_an(io_buffer, &gpus[gpu], isjson); +} - if (isjson) - sprintf(buf, "{\"CPU\":%d,\"MHS av\":%.2f,\"MHS %ds\":%.2f,\"Accepted\":%d,\"Rejected\":%d,\"Utility\":%.2f,\"Last Share Pool\":%d,\"Last Share Time\":%lu,\"Total MH\":%.4f}", - cpu, cgpu->total_mhashes / total_secs, - opt_log_interval, cgpu->rolling, - cgpu->accepted, cgpu->rejected, - cgpu->utility, - ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, - (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes); - else - sprintf(buf, "CPU=%d,MHS av=%.2f,MHS %ds=%.2f,Accepted=%d,Rejected=%d,Utility=%.2f,Last Share Pool=%d,Last Share Time=%lu,Total MH=%.4f%c", - cpu, cgpu->total_mhashes / total_secs, - opt_log_interval, cgpu->rolling, - cgpu->accepted, cgpu->rejected, - cgpu->utility, - ((unsigned long)(cgpu->last_share_pool_time) > 0) ? cgpu->last_share_pool : -1, - (unsigned long)(cgpu->last_share_pool_time), cgpu->total_mhashes, SEPARATOR); +static void pgastatus(int pga, bool isjson) +{ + int dev = pgadevice(pga); + if (dev < 0) // Should never happen + return; + devstatus_an(io_buffer, devices[dev], isjson); +} - strcat(io_buffer, buf); - } +static void cpustatus(int cpu, bool isjson) +{ + if (opt_n_threads <= 0 || cpu < 0 || cpu >= num_processors) + return; + devstatus_an(io_buffer, &cpus[cpu], isjson); } -#endif -static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) +static void +devinfo_internal(void (*func)(char*, struct cgpu_info*, bool), + __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson) { - int devcount = 0; int i; - if (nDevs == 0 && opt_n_threads == 0) { + if (total_devices == 0) { strcpy(io_buffer, message(MSG_NODEVS, 0, NULL, isjson)); return; } @@ -931,45 +902,29 @@ static void devstatus(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, b strcat(io_buffer, JSON_DEVS); } - for (i = 0; i < nDevs; i++) { - if (isjson && devcount > 0) + for (i = 0; i < total_devices; ++i) { + if (isjson && i) strcat(io_buffer, COMMA); - gpustatus(i, isjson); - - devcount++; + func(io_buffer, devices[i], isjson); } -#if defined(USE_BITFORCE) || defined(USE_ICARUS) - int numpga = numpgas(); - - if (numpga > 0) - for (i = 0; i < numpga; i++) { - if (isjson && devcount > 0) - strcat(io_buffer, COMMA); - - pgastatus(i, isjson); - - devcount++; - } -#endif - -#ifdef WANT_CPUMINE - if (opt_n_threads > 0) - for (i = 0; i < num_processors; i++) { - if (isjson && devcount > 0) - strcat(io_buffer, COMMA); - - cpustatus(i, isjson); - - devcount++; - } -#endif - if (isjson) strcat(io_buffer, JSON_CLOSE); } +static void +devdetail(SOCKETTYPE c, char *param, bool isjson) +{ + return devinfo_internal(devdetail_an, c, param, isjson); +} + +static void +devstatus(SOCKETTYPE c, char *param, bool isjson) +{ + return devinfo_internal(devstatus_an, c, param, isjson); +} + static void gpudev(__maybe_unused SOCKETTYPE c, char *param, bool isjson) { int id; @@ -1971,6 +1926,7 @@ struct CMDS { { "version", apiversion, false }, { "config", minerconfig, false }, { "devs", devstatus, false }, + { "devdetail", devdetail, false }, { "pools", poolstatus, false }, { "summary", summary, false }, { "gpuenable", gpuenable, true }, diff --git a/driver-opencl.c b/driver-opencl.c index da9a597ced..fca93eef71 100644 --- a/driver-opencl.c +++ b/driver-opencl.c @@ -1154,6 +1154,34 @@ static void get_opencl_statline(char *buf, struct cgpu_info *gpu) tailsprintf(buf, " I:%2d", gpu->intensity); } +static json_t* +get_opencl_extra_device_status(struct cgpu_info *gpu) +{ + json_t *info = json_object(); + + float gt, gv; + int ga, gf, gp, gc, gm, pt; +#ifdef HAVE_ADL + if (!gpu_stats(gpu->device_id, >, &gc, &gm, &gv, &ga, &gf, &gp, &pt)) +#endif + gt = gv = gm = gc = ga = gf = gp = pt = 0; + json_object_set(info, "Fan Speed", json_integer(gf)); + json_object_set(info, "Fan Percent", json_integer(gp)); + json_object_set(info, "GPU Clock", json_integer(gc)); + json_object_set(info, "Memory Clock", json_integer(gm)); + json_object_set(info, "GPU Voltage", json_real(gv)); + json_object_set(info, "GPU Activity", json_integer(ga)); + json_object_set(info, "Powertune", json_integer(pt)); + + json_object_set(info, "Intensity", + gpu->dynamic + ? json_string("D") + : json_integer(gpu->intensity) + ); + + return info; +} + struct opencl_thread_data { cl_int (*queue_kernel_parameters)(_clState *, dev_blk_ctx *, cl_uint); uint32_t *res; @@ -1434,6 +1462,7 @@ struct device_api opencl_api = { .get_statline_before = get_opencl_statline_before, #endif .get_statline = get_opencl_statline, + .get_extra_device_status = get_opencl_extra_device_status, .thread_prepare = opencl_thread_prepare, .thread_init = opencl_thread_init, .free_work = opencl_free_work, diff --git a/miner.h b/miner.h index 7d0354cc3f..b9bfb676a9 100644 --- a/miner.h +++ b/miner.h @@ -197,6 +197,8 @@ struct device_api { void (*reinit_device)(struct cgpu_info*); void (*get_statline_before)(char*, struct cgpu_info*); void (*get_statline)(char*, struct cgpu_info*); + json_t* (*get_extra_device_detail)(struct cgpu_info*); + json_t* (*get_extra_device_status)(struct cgpu_info*); // Thread-specific functions bool (*thread_prepare)(struct thr_info*);