From 04cf1d6de47e21b330f377b5e4f0d11cc638d4d9 Mon Sep 17 00:00:00 2001
From: "Suren A. Chilingaryan" <csa@dside.dyndns.org>
Date: Mon, 12 Dec 2011 16:34:33 +0100
Subject: Allow to configure the number of preprocessing threads

---
 cli.c                 | 25 ++++++++++++++++++++++---
 event.c               | 16 ++++++++++++++++
 event.h               |  5 +++++
 ipecamera/ipecamera.c |  7 ++++++-
 pcilib.h              |  8 ++++++++
 5 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/cli.c b/cli.c
index ae8da95..7101d6a 100644
--- a/cli.c
+++ b/cli.c
@@ -127,6 +127,7 @@ typedef enum {
     OPT_RUN_TIME,
     OPT_FORMAT,
     OPT_BUFFER,
+    OPT_THREADS,
     OPT_LIST_DMA,
     OPT_LIST_DMA_BUFFERS,
     OPT_READ_DMA_BUFFER,
@@ -167,6 +168,7 @@ static struct option long_options[] = {
     {"trigger-time",		required_argument, 0, OPT_TRIGGER_TIME },
     {"format",			required_argument, 0, OPT_FORMAT },
     {"buffer",			optional_argument, 0, OPT_BUFFER },
+    {"threads",			optional_argument, 0, OPT_THREADS },
     {"start-dma",		required_argument, 0, OPT_START_DMA },
     {"stop-dma",		optional_argument, 0, OPT_STOP_DMA },
     {"list-dma-engines",	no_argument, 0, OPT_LIST_DMA },
@@ -258,6 +260,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {
 "	add_header		- Prefix events with 256 bit header\n"
 //"	ringfs			- Write to RingFS\n"
 "   --buffer [size]		- Request data buffering, size in MB\n"
+"   --threads [num]		- Allow multithreaded processing\n"
 "\n"
 "  DMA Options:\n"
 "   --multipacket		- Read multiple packets\n"
@@ -1281,7 +1284,7 @@ void *Monitor(void *user) {
     return NULL;
 }
 
-int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *evname, const char *data_type, size_t num, size_t run_time, size_t trigger_time, pcilib_timeout_t timeout, PARTITION partition, FORMAT format, size_t buffer_size, FILE *ofile) {
+int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *evname, const char *data_type, size_t num, size_t run_time, size_t trigger_time, pcilib_timeout_t timeout, PARTITION partition, FORMAT format, size_t buffer_size, size_t threads, FILE *ofile) {
     int err;
     GRABContext ctx;
 //    void *data = NULL;
@@ -1346,7 +1349,10 @@ int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *evname, co
     if (flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) {
 	pcilib_configure_rawdata_callback(handle, &raw_data, NULL);
     }
-
+    
+    if (flags&PCILIB_EVENT_FLAG_PREPROCESS) {
+	pcilib_configure_preprocessing_threads(handle, threads);
+    }
     
     if (grab_mode&GRAB_MODE_TRIGGER) {
 	if (trigger_time) {
@@ -1903,6 +1909,7 @@ int main(int argc, char **argv) {
     size_t trigger_time = 0;
     size_t run_time = 0;
     size_t buffer = 0;
+    size_t threads = 1;
     FORMAT format = FORMAT_RAW;
     PARTITION partition = PARTITION_UNKNOWN;
     FLAGS flags = 0;
@@ -2227,6 +2234,18 @@ int main(int argc, char **argv) {
 		    buffer -= 128 + buffer/16;
 		}
 	    break;	   
+	    case OPT_THREADS:
+		if (optarg) num_offset = optarg;
+		else if ((optind < argc)&&(argv[optind][0] != '-')) num_offset = argv[optind++];
+		else num_offset = NULL;
+		
+		if (num_offset) {
+		    if ((!isnumber(num_offset))||(sscanf(num_offset, "%zu", &threads) != 1))
+			Usage(argc, argv, "Invalid threads number is specified (%s)", num_offset);
+		} else {
+		    threads = 0;
+		}
+	    break;	   
 	    case OPT_FORMAT:
 		if (!strcasecmp(optarg, "add_header")) format =  FORMAT_HEADER;
 		else if (!strcasecmp(optarg, "ringfs")) format =  FORMAT_RINGFS;
@@ -2454,7 +2473,7 @@ int main(int argc, char **argv) {
         pcilib_reset(handle);
      break;
      case MODE_GRAB:
-        TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, timeout, partition, format, buffer, ofile);
+        TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, timeout, partition, format, buffer, threads, ofile);
      break;
      case MODE_LIST_DMA:
         ListDMA(handle, fpga_device, model_info);
diff --git a/event.c b/event.c
index a277e46..9488eae 100644
--- a/event.c
+++ b/event.c
@@ -121,6 +121,22 @@ int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t
     return 0;    
 }
 
+int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+
+    api = model_info->event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    ctx->event_ctx->params.parallel.max_threads = max_threads;
+
+    return 0;
+}
+
 int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) {
     pcilib_event_api_description_t *api;
     
diff --git a/event.h b/event.h
index dfae452..3523f49 100644
--- a/event.h
+++ b/event.h
@@ -46,9 +46,14 @@ typedef struct {
     void *user;
 } pcilib_rawdata_parameters_t;
 
+typedef struct {
+    size_t max_threads;
+} pcilib_parallel_parameters_t;
+
 typedef struct {
     pcilib_autostop_parameters_t autostop;
     pcilib_rawdata_parameters_t rawdata;
+    pcilib_parallel_parameters_t parallel;
 } pcilib_event_parameters_t;
 
 struct pcilib_event_context_s {
diff --git a/ipecamera/ipecamera.c b/ipecamera/ipecamera.c
index c170174..d963494 100644
--- a/ipecamera/ipecamera.c
+++ b/ipecamera/ipecamera.c
@@ -407,12 +407,17 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev
     
     if (flags&PCILIB_EVENT_FLAG_PREPROCESS) {
 	ctx->n_preproc = pcilib_get_cpu_count();
+	
+	    // it would be greate to detect hyperthreading cores and ban them
 	switch (ctx->n_preproc) {
 	    case 1: break;
 	    case 2-3: ctx->n_preproc -= 1; break;
 	    default: ctx->n_preproc -= 2; break;
 	}
-	
+
+	if ((vctx->params.parallel.max_threads)&&(vctx->params.parallel.max_threads < ctx->n_preproc))
+	    ctx->n_preproc = vctx->params.parallel.max_threads;
+
 	ctx->preproc = (ipecamera_preprocessor_t*)malloc(ctx->n_preproc * sizeof(ipecamera_preprocessor_t));
 	if (!ctx->preproc) {
 	    ipecamera_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT);
diff --git a/pcilib.h b/pcilib.h
index e9cd4ec..fed600c 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -332,6 +332,14 @@ int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t
  */
 int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user);
 
+/*
+ * Configures maximal number of preprocessing threads. Actual amount of threads 
+ * may be bigger. For instance, additionaly a real-time reader thread will be 
+ * executed for most of hardware
+ */
+int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads);
+
+
 int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags);
 int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags);
 
-- 
cgit v1.2.3