/* * Copyright (c) 2001 Matteo Frigo * Copyright (c) 2001 Massachusetts Institute of Technology * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ /* $Id: problem.c,v 1.28 2006-01-04 00:34:04 athena Exp $ */ #include "config.h" #include "bench.h" #include #include #include #include typedef enum { SAME, PADDED, HALFISH } n_transform; /* funny transformations for last dimension of PROBLEM_REAL */ static int transform_n(int n, n_transform nt) { switch (nt) { case SAME: return n; case PADDED: return 2*(n/2+1); case HALFISH: return (n/2+1); default: BENCH_ASSERT(0); return 0; } } /* do what I mean */ static bench_tensor *dwim(bench_tensor *t, bench_iodim **last_iodim, n_transform nti, n_transform nto, bench_iodim *dt) { int i; bench_iodim *d, *d1; if (!FINITE_RNK(t->rnk) || t->rnk < 1) return t; i = t->rnk; d1 = *last_iodim; while (--i >= 0) { d = t->dims + i; if (!d->is) d->is = d1->is * transform_n(d1->n, d1==dt ? nti : SAME); if (!d->os) d->os = d1->os * transform_n(d1->n, d1==dt ? nto : SAME); d1 = d; } *last_iodim = d1; return t; } static void transpose_tensor(bench_tensor *t) { int i; if (!FINITE_RNK(t->rnk) || t->rnk < 1) return; t->dims[0].os = t->dims[t->rnk - 1].os; for (i = 1; i < t->rnk; ++i) t->dims[i].os = t->dims[i-1].os * t->dims[i-1].n; } static const char *parseint(const char *s, int *n) { int sign = 1; *n = 0; if (*s == '-') { sign = -1; ++s; } else if (*s == '+') { sign = +1; ++s; } BENCH_ASSERT(isdigit(*s)); while (isdigit(*s)) { *n = *n * 10 + (*s - '0'); ++s; } *n *= sign; if (*s == 'k' || *s == 'K') { *n *= 1024; ++s; } if (*s == 'm' || *s == 'M') { *n *= 1024 * 1024; ++s; } return s; } struct dimlist { bench_iodim car; r2r_kind_t k; struct dimlist *cdr; }; static const char *parsetensor(const char *s, bench_tensor **tp, r2r_kind_t **k) { struct dimlist *l = 0, *m; bench_tensor *t; int rnk = 0; L1: m = (struct dimlist *)bench_malloc(sizeof(struct dimlist)); /* nconc onto l */ m->cdr = l; l = m; ++rnk; s = parseint(s, &m->car.n); if (*s == ':') { /* read input stride */ ++s; s = parseint(s, &m->car.is); if (*s == ':') { /* read output stride */ ++s; s = parseint(s, &m->car.os); } else { /* default */ m->car.os = m->car.is; } } else { m->car.is = 0; m->car.os = 0; } if (*s == 'f' || *s == 'F') { m->k = R2R_R2HC; ++s; } else if (*s == 'b' || *s == 'B') { m->k = R2R_HC2R; ++s; } else if (*s == 'h' || *s == 'H') { m->k = R2R_DHT; ++s; } else if (*s == 'e' || *s == 'E' || *s == 'o' || *s == 'O') { char c = *(s++); int ab; s = parseint(s, &ab); if (c == 'e' || c == 'E') { if (ab == 0) m->k = R2R_REDFT00; else if (ab == 1) m->k = R2R_REDFT01; else if (ab == 10) m->k = R2R_REDFT10; else if (ab == 11) m->k = R2R_REDFT11; else BENCH_ASSERT(0); } else { if (ab == 0) m->k = R2R_RODFT00; else if (ab == 1) m->k = R2R_RODFT01; else if (ab == 10) m->k = R2R_RODFT10; else if (ab == 11) m->k = R2R_RODFT11; else BENCH_ASSERT(0); } } else m->k = R2R_R2HC; if (*s == 'x' || *s == 'X') { ++s; goto L1; } /* now we have a dimlist. Build bench_tensor, etc. */ if (k && rnk > 0) { int i; *k = (r2r_kind_t *) bench_malloc(sizeof(r2r_kind_t) * rnk); for (m = l, i = rnk - 1; i >= 0; --i, m = m->cdr) { BENCH_ASSERT(m); (*k)[i] = m->k; } } t = mktensor(rnk); while (--rnk >= 0) { bench_iodim *d = t->dims + rnk; BENCH_ASSERT(l); m = l; l = m->cdr; d->n = m->car.n; d->is = m->car.is; d->os = m->car.os; bench_free(m); } *tp = t; return s; } /* parse a problem description, return a problem */ bench_problem *problem_parse(const char *s) { bench_problem *p; bench_iodim last_iodim0 = {1,1,1}, *last_iodim = &last_iodim0; bench_iodim *sz_last_iodim; bench_tensor *sz; n_transform nti = SAME, nto = SAME; int transpose = 0; p = (bench_problem *) bench_malloc(sizeof(bench_problem)); p->kind = PROBLEM_COMPLEX; p->k = 0; p->sign = -1; p->in = p->out = 0; p->inphys = p->outphys = 0; p->in_place = 0; p->destroy_input = 0; p->split = 0; p->userinfo = 0; p->sz = p->vecsz = 0; p->ini = p->outi = 0; p->pstring = (char *) bench_malloc(sizeof(char) * (strlen(s) + 1)); strcpy(p->pstring, s); L1: switch (tolower(*s)) { case 'i': p->in_place = 1; ++s; goto L1; case 'o': p->in_place = 0; ++s; goto L1; case 'd': p->destroy_input = 1; ++s; goto L1; case '/': p->split = 1; ++s; goto L1; case 'f': case '-': p->sign = -1; ++s; goto L1; case 'b': case '+': p->sign = 1; ++s; goto L1; case 'r': p->kind = PROBLEM_REAL; ++s; goto L1; case 'c': p->kind = PROBLEM_COMPLEX; ++s; goto L1; case 'k': p->kind = PROBLEM_R2R; ++s; goto L1; case 't': transpose = 1; ++s; goto L1; default : ; } s = parsetensor(s, &sz, p->kind == PROBLEM_R2R ? &p->k : 0); if (p->kind == PROBLEM_REAL) { if (p->sign < 0) { nti = p->in_place ? PADDED : SAME; nto = HALFISH; } else { nti = HALFISH; nto = p->in_place ? PADDED : SAME; } } sz_last_iodim = sz->dims + sz->rnk - 1; if (*s == '*') { /* "external" vector */ ++s; p->sz = dwim(sz, &last_iodim, nti, nto, sz_last_iodim); s = parsetensor(s, &sz, 0); p->vecsz = dwim(sz, &last_iodim, nti, nto, sz_last_iodim); } else if (*s == 'v' || *s == 'V') { /* "internal" vector */ bench_tensor *vecsz; ++s; s = parsetensor(s, &vecsz, 0); p->vecsz = dwim(vecsz, &last_iodim, nti, nto, sz_last_iodim); p->sz = dwim(sz, &last_iodim, nti, nto, sz_last_iodim); } else { p->sz = dwim(sz, &last_iodim, nti, nto, sz_last_iodim); p->vecsz = mktensor(0); } if (transpose) { transpose_tensor(p->sz); transpose_tensor(p->vecsz); } if (!p->in_place) p->out = ((bench_real *) p->in) + (1 << 20); /* whatever */ BENCH_ASSERT(p->sz && p->vecsz); BENCH_ASSERT(!*s); return p; } void problem_destroy(bench_problem *p) { BENCH_ASSERT(p); problem_free(p); bench_free0(p->k); bench_free0(p->pstring); bench_free(p); }