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); } } }
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); } } }