int main (int argc, char ** argv) { mps_context * s = mps_context_new (); mps_thread_pool * pool = mps_thread_pool_new (s, 0); int i[N_THREADS]; int j; for(j = 0; j < N_THREADS; j++) i[j] = j; j = 0; printf (" => Created a thread pool with %d threads\n", pool->n); printf (" => Asking the threads to print an integer (from 0 to %d)...\n", N_THREADS - 1); for (j = 0; j < N_THREADS; j++) mps_thread_pool_assign (s, pool, (mps_thread_work) work, i + j); mps_thread_pool_wait (s, pool); printf ("\n => All the threads have completed their work\n"); printf (" => Doing it again (testing re-usability of the thread pool)\n"); for (j = 0; j < N_THREADS; j++) mps_thread_pool_assign (s, pool, (mps_thread_work) work, i + j); mps_thread_pool_wait (s, pool); printf ("\n => Trying to stop all the threads..."); mps_thread_pool_free (s, pool); printf ("done\n"); }
void mps_mpsolve_async (mps_context * s, mps_callback callback, void * user_data) { #ifdef MPS_CATCH_FPE feenableexcept (FE_INVALID|FE_DIVBYZERO|FE_OVERFLOW); #endif /* Set up callbacks */ s->callback = callback; s->user_data = user_data; mps_thread_pool * private_pool = mps_thread_pool_new (s, 1); s->self_thread_pool = private_pool; mps_thread_pool_assign (s, private_pool, (mps_thread_work) mps_caller, s); }
/** * @brief Improve all the approximations up to prec_out digits. * * For each approximation compute the value of sigma such that, given some * approximations \f$x_j\f$ of the roots, \f$r_j\f$ the values of the * inclusion radii and \f$d_i\f$ the number of correct digits: * \f[ * e_j < e_0 * \sigma^{2^j} \qquad \sigma=\frac{k}{k-1}=\frac{1}{1-t} \qquad k=\frac{1}{t} * \f] * and * \f[ * t = \min_j |z_i-z_j|-r_j * \f] * Then compute the number of digits needed for the j-th * iteration i.e., if \f$cond\f$ is the conditioning of the root: * \f[ * d_j = \log(\frac{e_j}{|x|}) + cond * \f] * where * \f[ * \log(\frac{e_j}{|x|}) = (f+g){2j} \qquad * cond = \log(\frac{rad}{\epsilon}) * \f] * and * \f[ * cond \approx \lVert p \rVert (1+ \frac{|x_i|}{a_n \prod_{j \neq i} |x_i-x_j|} * \f] * and * \f[ * cond \approx \frac{r_i}{\epsilon |x_i|} * \f] * for user-defined polynomials. * * <code>s->mpwp</code> denotes the number of bits of the current working * precision. * * @param ctx The mps_context associated with the computation. */ MPS_PRIVATE void mps_improve (mps_context * ctx) { int i; long int current_precision = 0L; int approximated_roots = 0; mps_polynomial * p = ctx->active_poly; rdpe_t * root_conditioning = NULL; ctx->operation = MPS_OPERATION_REFINEMENT; /* We need to be able to evaluate the Newton correction in a point * in order to perform the refinement. This is not necessary true * for custom polynomial types, so add a check in here */ if (p->mnewton == NULL && p->density != MPS_DENSITY_USER) return; /* Set lastphase to mp */ ctx->lastphase = mp_phase; /* Determine the conditioning of the roots */ root_conditioning = evaluate_root_conditioning (ctx, p, ctx->root, ctx->n); /* We adopt the strategy of various iterations refinements on * the approximations by setting the precision of the input * polynomial in an increasing sequence. */ /* We start by determining the minimum precision at which we can * extract some information. */ current_precision = LONG_MAX; for (i = 0; i < ctx->n; i++) { if (ctx->root[i]->wp < current_precision) current_precision = ctx->root[i]->wp; if (MPS_ROOT_STATUS_IS_APPROXIMATED (ctx->root[i]->status) || ctx->root[i]->inclusion == MPS_ROOT_INCLUSION_OUT) approximated_roots++; } /* Start by iterating on the roots that are not approximated, and * continue until we get all of them. */ while (approximated_roots < ctx->n) { mps_polynomial_raise_data (ctx, p, current_precision); MPS_DEBUG (ctx, "Step of improvement"); for (i = 0; i < ctx->n; i++) if (ctx->root[i]->status == MPS_ROOT_STATUS_ISOLATED && ctx->root[i]->inclusion != MPS_ROOT_INCLUSION_OUT) { /* Evaluate the necessary precision to iterate on this root. * If the the current polynomial precision is enough, iterate on it. * Otherwise, let it for the next round. */ long int necessary_precision = get_approximated_bits (ctx->root[i]) + log2 (ctx->n) + rdpe_log (root_conditioning[i]) / LOG2; if (necessary_precision < current_precision) { __improve_root_data * data = mps_new (__improve_root_data); data->ctx = ctx; data->p = p; data->root = ctx->root[i]; data->precision = current_precision; mps_thread_pool_assign (ctx, NULL, improve_root_wrapper, data); } } mps_thread_pool_wait (ctx, ctx->pool); for (i = 0; i < ctx->n; i++) if (!MPS_ROOT_STATUS_IS_APPROXIMATED (ctx->root[i]->status) && get_approximated_bits (ctx->root[i]) >= ctx->output_config->prec) { ctx->root[i]->status = MPS_ROOT_STATUS_APPROXIMATED; approximated_roots++; if (ctx->debug_level & MPS_DEBUG_IMPROVEMENT) MPS_DEBUG (ctx, "Approximated roots = %d", approximated_roots); } /* Increase precision to reach the desired number of approximated roots */ current_precision = 2 * current_precision; /* Check if we have gone too far with the precision, and we have gone over * the maximum precision allowed for this polynomial. */ if (current_precision > p->prec && p->prec != 0) { ctx->over_max = true; goto cleanup; } /* Increase data prec max that will be useful to the end user to know * the precision needed to hold these approximations. */ ctx->data_prec_max.value = current_precision; if (ctx->debug_level & MPS_DEBUG_IMPROVEMENT) MPS_DEBUG (ctx, "Increasing precision to %ld", current_precision); } cleanup: free (root_conditioning); }
/** * @brief Drop-in threaded replacement for the stock mpolzer. */ MPS_PRIVATE void mps_thread_mpolzer (mps_context * s, int *it, mps_boolean * excep, int required_zeros) { int i, nzeros = 0, n_threads = s->n_threads; *it = 0; *excep = false; /* Check if we have already approxmiated roots */ for (i = 0; i < s->n; i++) if (!s->root[i]->again) nzeros++; if (nzeros == s->n) { return; } /* Lower the number of threads if there are a lot of approximated roots */ if (s->n_threads > (s->n - nzeros)) n_threads = s->n - nzeros; else n_threads = s->n_threads; MPS_DEBUG_WITH_INFO (s, "Spawning %d worker", n_threads); mps_thread_worker_data *data; /* Allocate and the init mutexes needed by the routine */ pthread_mutex_t *roots_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); pthread_mutex_t *aberth_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); pthread_mutex_t global_aberth_mutex = PTHREAD_MUTEX_INITIALIZER; for (i = 0; i < s->n; i++) { pthread_mutex_init (&aberth_mutex[i], NULL); pthread_mutex_init (&roots_mutex[i], NULL); } /* Create a new work queue */ mps_thread_job_queue *queue = mps_thread_job_queue_new (s); data = (mps_thread_worker_data*)mps_malloc (sizeof(mps_thread_worker_data) * n_threads); /* Set data to be passed to every thread and actually spawn the threads. */ for (i = 0; i < n_threads; i++) { data[i].it = it; data[i].nzeros = &nzeros; data[i].s = s; data[i].excep = excep; data[i].thread = i; data[i].n_threads = n_threads; data[i].aberth_mutex = aberth_mutex; data[i].global_aberth_mutex = &global_aberth_mutex; data[i].queue = queue; data[i].roots_mutex = roots_mutex; data[i].required_zeros = required_zeros; mps_thread_pool_assign (s, s->pool, mps_thread_mpolzer_worker, data + i); } /* Wait for the threads to complete */ mps_thread_pool_wait (s, s->pool); /* Free data and exit */ free (data); for (i = 0; i < s->n; i++) { pthread_mutex_destroy (&roots_mutex[i]); pthread_mutex_destroy (&aberth_mutex[i]); } free (roots_mutex); free (aberth_mutex); mps_thread_job_queue_free (queue); }
/** * @brief Multithread version of mps_dpolzer (). */ MPS_PRIVATE void mps_thread_dpolzer (mps_context * s, int *it, mps_boolean * excep, int required_zeros) { mps_thread_worker_data *data; pthread_mutex_t *aberth_mutex, *roots_mutex; int i, nzeros = 0; /* initialize the iteration counter */ *it = 0; *excep = false; /* count the number of approximations in the root neighbourhood */ for (i = 0; i < s->n; i++) if (!s->root[i]->again) nzeros++; if (nzeros == s->n) return; /* Prepare queue */ mps_thread_job_queue *queue = mps_thread_job_queue_new (s); /* Allocate space for thread data */ data = (mps_thread_worker_data*)mps_malloc (sizeof(mps_thread_worker_data) * s->n_threads); /* Allocate mutexes and init them */ aberth_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); roots_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); for (i = 0; i < s->n; i++) { if (s->pool->n > 1) { pthread_mutex_init (&aberth_mutex[i], NULL); pthread_mutex_init (&roots_mutex[i], NULL); } } /* Start spawning thread */ for (i = 0; i < s->n_threads; i++) { data[i].aberth_mutex = aberth_mutex; data[i].excep = excep; data[i].it = it; data[i].n_threads = s->n_threads; data[i].nzeros = &nzeros; data[i].queue = queue; data[i].roots_mutex = roots_mutex; data[i].s = s; data[i].thread = i; data[i].required_zeros = required_zeros; mps_thread_pool_assign (s, s->pool, mps_thread_dpolzer_worker, data + i); } /* Wait for the thread to complete */ mps_thread_pool_wait (s, s->pool); free (aberth_mutex); free (roots_mutex); free (data); mps_thread_job_queue_free (queue); }
/** * @brief Drop-in replacement for the stock fpolzer routine. * This version adds multithread support. */ MPS_PRIVATE void mps_thread_fpolzer (mps_context * s, int *it, mps_boolean * excep, int required_zeros) { int i, nzeros = 0, n_threads = s->n_threads; mps_thread_worker_data *data; pthread_mutex_t *aberth_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); pthread_mutex_t *roots_mutex = (pthread_mutex_t*)mps_malloc (sizeof(pthread_mutex_t) * s->n); for (i = 0; i < s->n; i++) { pthread_mutex_init (roots_mutex + i, NULL); pthread_mutex_init (aberth_mutex + i, NULL); } /* Create a new job queue */ mps_thread_job_queue *queue = mps_thread_job_queue_new (s); *it = 0; *excep = false; /* count the number of approximations in the root neighbourhood */ for (i = 0; i < s->n; i++) if (!s->root[i]->again) nzeros++; if (nzeros == s->n) { free (roots_mutex); free (aberth_mutex); mps_thread_job_queue_free (queue); return; } data = (mps_thread_worker_data*)mps_malloc (sizeof(mps_thread_worker_data) * n_threads); for (i = 0; i < n_threads; i++) { data[i].it = it; data[i].nzeros = &nzeros; data[i].s = s; data[i].excep = excep; data[i].thread = i; data[i].n_threads = n_threads; data[i].aberth_mutex = aberth_mutex; data[i].roots_mutex = roots_mutex; data[i].queue = queue; data[i].required_zeros = required_zeros; /* pthread_create (&threads[i], NULL, &mps_thread_fpolzer_worker, */ /* data + i); */ mps_thread_pool_assign (s, s->pool, mps_thread_fpolzer_worker, data + i); } mps_thread_pool_wait (s, s->pool); free (data); free (roots_mutex); free (aberth_mutex); mps_thread_job_queue_free (queue); }