Ejemplo n.º 1
0
static void _ewma_verdict(struct spi *spi, struct spi_classresult *cr)
{
	struct verdict *v = spi->vdata;
	struct ewma_verdict *ev = cr->ep->vdata;
	int i;
	double m1 = 0.0, m2 = 0.0;
	spi_label_t max_label = 0;

	/* special case if its first verdict request */
	if (!ev) {
		ev = mmatic_zalloc(cr->ep->mm, sizeof *ev);
		cr->ep->vdata = ev;

		/* init EWMA with class. result */
		memcpy(ev->cprob, cr->cprob, sizeof(spi_cprob_t));

		/* fall-back on simple verdict */
		_simple_verdict(spi, cr);
	} else {
		/* update EWMA */
		for (i = 1; i <= SPI_LABEL_MAX; i++) {
			ev->cprob[i] = EWMA(ev->cprob[i], cr->cprob[i], v->ewma.N);

			/* collect info as _cprob_dist() */
			if (ev->cprob[i] > m2) {
				if (ev->cprob[i] > m1) {
					max_label = i;
					m2 = m1;
					m1 = ev->cprob[i];
				} else {
					m2 = ev->cprob[i];
				}
			}
		}

		if (m1 - m2 > cr->ep->verdict_prob) {
			cr->ep->verdict = max_label;
			cr->ep->verdict_prob = (m1 - m2);
		}
	}
}
Ejemplo n.º 2
0
static void *
thread_pool(void *arg)
{
	int ret;
	pool_ctx_t *pool_ctx = NULL;
	edict_message_t message;
	edict_t *edict = NULL;
	thread_ctx_t thread_ctx = { NULL };
	watchdog_t *dogp;
	bool process;
	struct timespec now;
	int waited;
	int lastseenms;

	pool_ctx = (pool_ctx_t *)arg;
	assert(pool_ctx->mx);
	assert(pool_ctx->routine);
	assert(pool_ctx->info);

	POOL_MUTEX_LOCK;
	pool_ctx->count_thread++;

	if (pool_ctx->watchdog_time) {
		/* add the watchdog info for this thread */
		dogp = pool_ctx->wdlist;
		pool_ctx->wdlist = &thread_ctx.watchdog;
		pool_ctx->wdlist->next = dogp;
		clock_gettime(CLOCK_TYPE, &thread_ctx.watchdog.last_seen);
		thread_ctx.watchdog.tid = pthread_self();
	}

	/* idle check reference time */
	clock_gettime(CLOCK_TYPE, &pool_ctx->last_idle_check);
	POOL_MUTEX_UNLOCK;

	logstr(GLOG_DEBUG, "threadpool '%s' thread #%d starting%s", pool_ctx->info->name,
	    pool_ctx->count_thread, pool_ctx->watchdog_time ? " watchdog enabled" : "");

	for (;;) {
		/* check if there are too many idling threads */
		POOL_MUTEX_LOCK;

		/* kick the watchdog */
		if (pool_ctx->watchdog_time)
			clock_gettime(CLOCK_TYPE, &thread_ctx.watchdog.last_seen);

		clock_gettime(CLOCK_TYPE, &now);
		waited = ms_diff(&now, &pool_ctx->last_idle_check);

		if (waited > IDLETIME) {
			/* update the reference time */
			clock_gettime(CLOCK_TYPE, &pool_ctx->last_idle_check);

			if (pool_ctx->watchdog_time) {
				/* check the watchdog status */
				dogp = pool_ctx->wdlist;
				while (dogp) {
					lastseenms = ms_diff(&now, &dogp->last_seen);
					if (lastseenms > pool_ctx->watchdog_time) {
						/* a stuck thread */
						logstr(GLOG_WARNING,
						    "thread #%x of pool '%s' stuck, last seen %d ms ago.",
						    (uint32_t) dogp->tid, pool_ctx->info->name, lastseenms);
						pthread_kill(dogp->tid, SIGALRM);
					}
					dogp = dogp->next;
				}
			}

			if (pool_ctx->count_thread > 8 && pool_ctx->ewma_idle > pool_ctx->count_thread / 2) {
				/* prepare for shutdown */
				pool_ctx->count_thread--;
				/*
				 * update the moving average by decrementing it
				 * brutal, but efficient for the purpose
				 */
				pool_ctx->ewma_idle--;
				if (pool_ctx->watchdog_time) {
					/*
					 * remove thread from the watchdoglist
					 * do not Free(), the block is reserved from the stack 
					 */
					dogp = pool_ctx->wdlist;
					if (dogp->tid == pthread_self()) {
						/* first node */
						pool_ctx->wdlist = pool_ctx->wdlist->next;
					} else {
						while (dogp->next) {
							if (dogp->next->tid == pthread_self()) {
								dogp->next = dogp->next->next;
								break;
							}
							dogp = dogp->next;
						}
					}
				}
				POOL_MUTEX_UNLOCK;
				logstr(GLOG_DEBUG, "threadpool '%s' thread shutting down",
				    pool_ctx->info->name);
				/* run a cleanup routine if defined */
				if (thread_ctx.cleanup)
					thread_ctx.cleanup(thread_ctx.state);
				pthread_exit(NULL);
			}
		}
		/* update the moving average */
		EWMA(pool_ctx->ewma_idle, pool_ctx->count_idle);
		pool_ctx->count_idle++;
		POOL_MUTEX_UNLOCK;

		/* wait for new jobs */
		ret =
		    get_msg_timed(pool_ctx->info->work_queue_id, &message, sizeof(message.edict),
		    IDLETIME);

		POOL_MUTEX_LOCK;
		/* kick the watchdog */
		if (pool_ctx->watchdog_time)
			clock_gettime(CLOCK_TYPE, &thread_ctx.watchdog.last_seen);
		pool_ctx->count_idle--;
		POOL_MUTEX_UNLOCK;

		process = true;

		if (ret > 0) {
			/* we've got a message */
			edict = message.edict;
			assert(edict->job);

			logstr(GLOG_DEBUG, "threadpool '%s' processing", pool_ctx->info->name);

			POOL_MUTEX_LOCK;
			if (pool_ctx->count_idle < 1) {
				/* We were the last idling thread, start another */
				if (pool_ctx->count_thread <= pool_ctx->max_thread
				    || 0 == pool_ctx->max_thread) {
					logstr(GLOG_DEBUG, "threadpool '%s' starting another thread",
					    pool_ctx->info->name);
					create_thread(NULL, DETACH, &thread_pool, pool_ctx);
				} else {
					logstr(GLOG_ERROR,
					    "threadpool '%s': maximum thread count (%d) reached",
					    pool_ctx->info->name, pool_ctx->max_thread);
					process = false;
				}
			}
			POOL_MUTEX_UNLOCK;

			/* run the routine with args */
			if (process) {
				pool_ctx->routine(pool_ctx->info, &thread_ctx, edict);
			} else if (edict->resultmq >= 0) {
				/* failed, and we can inform the caller */
				send_result(edict, NULL);
			}

			/* we are done */
			edict_unlink(edict);
		} else {
			/* timeout occurred */
			logstr(GLOG_INSANE, "threadpool '%s' idling", pool_ctx->info->name);
		}
	}
}