📄 putils.c
字号:
/* * Copyright (c) 1997-1999, 2003 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 * *//* * putils.c -- plan utilities shared by planner.c and rplanner.c *//* $Id: putils.c,v 1.21 2003/03/16 23:43:46 stevenj Exp $ */#include "fftw-int.h"#include <stdlib.h>#include <stdio.h>int fftw_node_cnt = 0;int fftw_plan_cnt = 0;/* * These two constants are used for the FFTW_ESTIMATE flag to help * create a heuristic plan. They don't affect FFTW_MEASURE. */#define NOTW_OPTIMAL_SIZE 32#define TWIDDLE_OPTIMAL_SIZE 12#define IS_POWER_OF_TWO(n) (((n) & ((n) - 1)) == 0)/* constructors --- I wish I had ML */fftw_plan_node *fftw_make_node(void){ fftw_plan_node *p = (fftw_plan_node *) fftw_malloc(sizeof(fftw_plan_node)); p->refcnt = 0; fftw_node_cnt++; return p;}void fftw_use_node(fftw_plan_node *p){ ++p->refcnt;}fftw_plan_node *fftw_make_node_notw(int size, const fftw_codelet_desc *config){ fftw_plan_node *p = fftw_make_node(); p->type = config->type; p->nodeu.notw.size = size; p->nodeu.notw.codelet = (fftw_notw_codelet *) config->codelet; p->nodeu.notw.codelet_desc = config; return p;}fftw_plan_node *fftw_make_node_real2hc(int size, const fftw_codelet_desc *config){ fftw_plan_node *p = fftw_make_node(); p->type = config->type; p->nodeu.real2hc.size = size; p->nodeu.real2hc.codelet = (fftw_real2hc_codelet *) config->codelet; p->nodeu.real2hc.codelet_desc = config; return p;}fftw_plan_node *fftw_make_node_hc2real(int size, const fftw_codelet_desc *config){ fftw_plan_node *p = fftw_make_node(); p->type = config->type; p->nodeu.hc2real.size = size; p->nodeu.hc2real.codelet = (fftw_hc2real_codelet *) config->codelet; p->nodeu.hc2real.codelet_desc = config; return p;}fftw_plan_node *fftw_make_node_twiddle(int n, const fftw_codelet_desc *config, fftw_plan_node *recurse, int flags){ fftw_plan_node *p = fftw_make_node(); p->type = config->type; p->nodeu.twiddle.size = config->size; p->nodeu.twiddle.codelet = (fftw_twiddle_codelet *) config->codelet; p->nodeu.twiddle.recurse = recurse; p->nodeu.twiddle.codelet_desc = config; fftw_use_node(recurse); if (flags & FFTW_MEASURE) p->nodeu.twiddle.tw = fftw_create_twiddle(n, config); else p->nodeu.twiddle.tw = 0; return p;}fftw_plan_node *fftw_make_node_hc2hc(int n, fftw_direction dir, const fftw_codelet_desc *config, fftw_plan_node *recurse, int flags){ fftw_plan_node *p = fftw_make_node(); p->type = config->type; p->nodeu.hc2hc.size = config->size; p->nodeu.hc2hc.dir = dir; p->nodeu.hc2hc.codelet = (fftw_hc2hc_codelet *) config->codelet; p->nodeu.hc2hc.recurse = recurse; p->nodeu.hc2hc.codelet_desc = config; fftw_use_node(recurse); if (flags & FFTW_MEASURE) p->nodeu.hc2hc.tw = fftw_create_twiddle(n, config); else p->nodeu.hc2hc.tw = 0; return p;}fftw_plan_node *fftw_make_node_generic(int n, int size, fftw_generic_codelet *codelet, fftw_plan_node *recurse, int flags){ fftw_plan_node *p = fftw_make_node(); p->type = FFTW_GENERIC; p->nodeu.generic.size = size; p->nodeu.generic.codelet = codelet; p->nodeu.generic.recurse = recurse; fftw_use_node(recurse); if (flags & FFTW_MEASURE) p->nodeu.generic.tw = fftw_create_twiddle(n, (const fftw_codelet_desc *) 0); else p->nodeu.generic.tw = 0; return p;}fftw_plan_node *fftw_make_node_rgeneric(int n, int size, fftw_direction dir, fftw_rgeneric_codelet *codelet, fftw_plan_node *recurse, int flags){ fftw_plan_node *p = fftw_make_node(); if (size % 2 == 0 || (n / size) % 2 == 0) fftw_die("invalid size for rgeneric codelet\n"); p->type = FFTW_RGENERIC; p->nodeu.rgeneric.size = size; p->nodeu.rgeneric.dir = dir; p->nodeu.rgeneric.codelet = codelet; p->nodeu.rgeneric.recurse = recurse; fftw_use_node(recurse); if (flags & FFTW_MEASURE) p->nodeu.rgeneric.tw = fftw_create_twiddle(n, (const fftw_codelet_desc *) 0); else p->nodeu.rgeneric.tw = 0; return p;}/* * Note that these two Rader-related things must go here, rather than * in rader.c, in order that putils.c (and rplanner.c) won't depend * upon rader.c. */fftw_rader_data *fftw_rader_top = NULL;static void fftw_destroy_rader(fftw_rader_data * d){ if (d) { d->refcount--; if (d->refcount <= 0) { fftw_rader_data *cur = fftw_rader_top, *prev = NULL; while (cur && cur != d) { prev = cur; cur = cur->next; } if (!cur) fftw_die("invalid Rader data pointer\n"); if (prev) prev->next = d->next; else fftw_rader_top = d->next; fftw_destroy_plan_internal(d->plan); fftw_free(d->omega); fftw_free(d->cdesc); fftw_free(d); } }}static void destroy_tree(fftw_plan_node *p){ if (p) { --p->refcnt; if (p->refcnt == 0) { switch (p->type) { case FFTW_NOTW: case FFTW_REAL2HC: case FFTW_HC2REAL: break; case FFTW_TWIDDLE: if (p->nodeu.twiddle.tw) fftw_destroy_twiddle(p->nodeu.twiddle.tw); destroy_tree(p->nodeu.twiddle.recurse); break; case FFTW_HC2HC: if (p->nodeu.hc2hc.tw) fftw_destroy_twiddle(p->nodeu.hc2hc.tw); destroy_tree(p->nodeu.hc2hc.recurse); break; case FFTW_GENERIC: if (p->nodeu.generic.tw) fftw_destroy_twiddle(p->nodeu.generic.tw); destroy_tree(p->nodeu.generic.recurse); break; case FFTW_RADER: if (p->nodeu.rader.tw) fftw_destroy_twiddle(p->nodeu.rader.tw); if (p->nodeu.rader.rader_data) fftw_destroy_rader(p->nodeu.rader.rader_data); destroy_tree(p->nodeu.rader.recurse); break; case FFTW_RGENERIC: if (p->nodeu.rgeneric.tw) fftw_destroy_twiddle(p->nodeu.rgeneric.tw); destroy_tree(p->nodeu.rgeneric.recurse); break; } fftw_free(p); fftw_node_cnt--; } }}/* create a plan with twiddle factors, and other bells and whistles */fftw_plan fftw_make_plan(int n, fftw_direction dir, fftw_plan_node *root, int flags, enum fftw_node_type wisdom_type, int wisdom_signature, fftw_recurse_kind recurse_kind, int vector_size){ fftw_plan p = (fftw_plan) fftw_malloc(sizeof(struct fftw_plan_struct)); p->n = n; p->dir = dir; p->flags = flags; fftw_use_node(root); p->root = root; p->cost = 0.0; p->wisdom_type = wisdom_type; p->wisdom_signature = wisdom_signature; p->recurse_kind = recurse_kind; p->vector_size = vector_size; if (recurse_kind == FFTW_VECTOR_RECURSE && vector_size > 1) fftw_die("invalid vector-recurse plan attempted\n"); p->next = (fftw_plan) 0; p->refcnt = 0; fftw_plan_cnt++; return p;}/* * complete with twiddle factors (because nodes don't have * them when FFTW_ESTIMATE is set) */void fftw_complete_twiddle(fftw_plan_node *p, int n){ int r; switch (p->type) { case FFTW_NOTW: case FFTW_REAL2HC: case FFTW_HC2REAL: break; case FFTW_TWIDDLE: r = p->nodeu.twiddle.size; if (!p->nodeu.twiddle.tw) p->nodeu.twiddle.tw = fftw_create_twiddle(n, p->nodeu.twiddle.codelet_desc); fftw_complete_twiddle(p->nodeu.twiddle.recurse, n / r); break; case FFTW_HC2HC: r = p->nodeu.hc2hc.size; if (!p->nodeu.hc2hc.tw) p->nodeu.hc2hc.tw = fftw_create_twiddle(n, p->nodeu.hc2hc.codelet_desc); fftw_complete_twiddle(p->nodeu.hc2hc.recurse, n / r); break; case FFTW_GENERIC: r = p->nodeu.generic.size; if (!p->nodeu.generic.tw) p->nodeu.generic.tw = fftw_create_twiddle(n, (const fftw_codelet_desc *) 0); fftw_complete_twiddle(p->nodeu.generic.recurse, n / r); break; case FFTW_RADER: r = p->nodeu.rader.size; if (!p->nodeu.rader.tw) p->nodeu.rader.tw = fftw_create_twiddle(n, p->nodeu.rader.rader_data->cdesc); fftw_complete_twiddle(p->nodeu.rader.recurse, n / r); break; case FFTW_RGENERIC: r = p->nodeu.rgeneric.size; if (!p->nodeu.rgeneric.tw) p->nodeu.rgeneric.tw = fftw_create_twiddle(n, (const fftw_codelet_desc *) 0); fftw_complete_twiddle(p->nodeu.rgeneric.recurse, n / r); break; }}void fftw_use_plan(fftw_plan p){ ++p->refcnt;}void fftw_destroy_plan_internal(fftw_plan p){ --p->refcnt; if (p->refcnt == 0) { destroy_tree(p->root); fftw_plan_cnt--; fftw_free(p); }}/* end of constructors *//* management of plan tables */void fftw_make_empty_table(fftw_plan *table){ *table = (fftw_plan) 0;}void fftw_insert(fftw_plan *table, fftw_plan this_plan){ fftw_use_plan(this_plan); this_plan->next = *table; *table = this_plan;}fftw_plan fftw_lookup(fftw_plan *table, int n, int flags, int vector_size){ fftw_plan p; for (p = *table; p && (p->n != n || p->flags != flags || p->vector_size != vector_size); p = p->next); return p;}void fftw_destroy_table(fftw_plan *table){ fftw_plan p, q; for (p = *table; p; p = q) { q = p->next; fftw_destroy_plan_internal(p); }}double fftw_estimate_node(fftw_plan_node *p){ int k; switch (p->type) { case FFTW_NOTW: k = p->nodeu.notw.size; goto common1; case FFTW_REAL2HC: k = p->nodeu.real2hc.size; goto common1; case FFTW_HC2REAL: k = p->nodeu.hc2real.size; common1: return 1.0 + 0.1 * (k - NOTW_OPTIMAL_SIZE) * (k - NOTW_OPTIMAL_SIZE); case FFTW_TWIDDLE: k = p->nodeu.twiddle.size; return 1.0 + 0.1 * (k - TWIDDLE_OPTIMAL_SIZE) * (k - TWIDDLE_OPTIMAL_SIZE) + fftw_estimate_node(p->nodeu.twiddle.recurse); case FFTW_HC2HC: k = p->nodeu.hc2hc.size; return 1.0 + 0.1 * (k - TWIDDLE_OPTIMAL_SIZE) * (k - TWIDDLE_OPTIMAL_SIZE) + fftw_estimate_node(p->nodeu.hc2hc.recurse); case FFTW_GENERIC: k = p->nodeu.generic.size; return 10.0 + k * k + fftw_estimate_node(p->nodeu.generic.recurse); case FFTW_RADER: k = p->nodeu.rader.size; return 10.0 + 10 * k + fftw_estimate_node(p->nodeu.rader.recurse); case FFTW_RGENERIC: k = p->nodeu.rgeneric.size; return 10.0 + k * k + fftw_estimate_node(p->nodeu.rgeneric.recurse); } return 1.0E20;}/* pick the better of two plans and destroy the other one. */fftw_plan fftw_pick_better(fftw_plan p1, fftw_plan p2){ if (!p1) return p2; if (!p2) return p1; if (p1->cost > p2->cost) { fftw_destroy_plan_internal(p1); return p2; } else { fftw_destroy_plan_internal(p2); return p1; }}/* find the smallest prime factor of n */int fftw_factor(int n){ int r; /* try 2 */ if ((n & 1) == 0) return 2; /* try odd numbers up to sqrt(n) */ for (r = 3; r * r <= n; r += 2) if (n % r == 0) return r; /* n is prime */ return n;}static void print_node(FILE *f, fftw_plan_node *p, int indent){ if (p) { switch (p->type) { case FFTW_NOTW: fprintf(f, "%*sFFTW_NOTW %d\n", indent, "", p->nodeu.notw.size); break; case FFTW_REAL2HC: fprintf(f, "%*sFFTW_REAL2HC %d\n", indent, "", p->nodeu.real2hc.size); break; case FFTW_HC2REAL: fprintf(f, "%*sFFTW_HC2REAL %d\n", indent, "", p->nodeu.hc2real.size); break; case FFTW_TWIDDLE: fprintf(f, "%*sFFTW_TWIDDLE %d\n", indent, "", p->nodeu.twiddle.size); print_node(f, p->nodeu.twiddle.recurse, indent); break; case FFTW_HC2HC: fprintf(f, "%*sFFTW_HC2HC %d\n", indent, "", p->nodeu.hc2hc.size); print_node(f, p->nodeu.hc2hc.recurse, indent); break; case FFTW_GENERIC: fprintf(f, "%*sFFTW_GENERIC %d\n", indent, "", p->nodeu.generic.size); print_node(f, p->nodeu.generic.recurse, indent); break; case FFTW_RADER: fprintf(f, "%*sFFTW_RADER %d\n", indent, "", p->nodeu.rader.size); fprintf(f, "%*splan for size %d convolution:\n", indent + 4, "", p->nodeu.rader.size - 1); print_node(f, p->nodeu.rader.rader_data->plan->root, indent + 6); print_node(f, p->nodeu.rader.recurse, indent); break; case FFTW_RGENERIC: fprintf(f, "%*sFFTW_RGENERIC %d\n", indent, "", p->nodeu.rgeneric.size); print_node(f, p->nodeu.rgeneric.recurse, indent); break; } }}void fftw_fprint_plan(FILE *f, fftw_plan p){ fprintf(f, "plan: (cost = %e)\n", p->cost); if (p->recurse_kind == FFTW_VECTOR_RECURSE) fprintf(f, "(vector recursion)\n"); else if (p->vector_size > 1) fprintf(f, "(vector-size %d)\n", p->vector_size); print_node(f, p->root, 0);}void fftw_print_plan(fftw_plan p){ fftw_fprint_plan(stdout, p);}size_t fftw_sizeof_fftw_real(void){ return(sizeof(fftw_real));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -