Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2003, 2007-14 Matteo Frigo |
3 | | * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology |
4 | | * |
5 | | * This program is free software; you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation; either version 2 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program; if not, write to the Free Software |
17 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
18 | | * |
19 | | */ |
20 | | |
21 | | #include "api/api.h" |
22 | | |
23 | | static planner_hook_t before_planner_hook = 0, after_planner_hook = 0; |
24 | | |
25 | | void X(set_planner_hooks)(planner_hook_t before, planner_hook_t after) |
26 | 0 | { |
27 | 0 | before_planner_hook = before; |
28 | 0 | after_planner_hook = after; |
29 | 0 | } |
30 | | |
31 | | static plan *mkplan0(planner *plnr, unsigned flags, |
32 | | const problem *prb, unsigned hash_info, |
33 | | wisdom_state_t wisdom_state) |
34 | 570 | { |
35 | | /* map API flags into FFTW flags */ |
36 | 570 | X(mapflags)(plnr, flags); |
37 | | |
38 | 570 | plnr->flags.hash_info = hash_info; |
39 | 570 | plnr->wisdom_state = wisdom_state; |
40 | | |
41 | | /* create plan */ |
42 | 570 | return plnr->adt->mkplan(plnr, prb); |
43 | 570 | } |
44 | | |
45 | | static unsigned force_estimator(unsigned flags) |
46 | 0 | { |
47 | 0 | flags &= ~(FFTW_MEASURE | FFTW_PATIENT | FFTW_EXHAUSTIVE); |
48 | 0 | return (flags | FFTW_ESTIMATE); |
49 | 0 | } |
50 | | |
51 | | static plan *mkplan(planner *plnr, unsigned flags, |
52 | | const problem *prb, unsigned hash_info) |
53 | 570 | { |
54 | 570 | plan *pln; |
55 | | |
56 | 570 | pln = mkplan0(plnr, flags, prb, hash_info, WISDOM_NORMAL); |
57 | | |
58 | 570 | if (plnr->wisdom_state == WISDOM_NORMAL && !pln) { |
59 | | /* maybe the planner failed because of inconsistent wisdom; |
60 | | plan again ignoring infeasible wisdom */ |
61 | 0 | pln = mkplan0(plnr, force_estimator(flags), prb, |
62 | 0 | hash_info, WISDOM_IGNORE_INFEASIBLE); |
63 | 0 | } |
64 | | |
65 | 570 | if (plnr->wisdom_state == WISDOM_IS_BOGUS) { |
66 | | /* if the planner detected a wisdom inconsistency, |
67 | | forget all wisdom and plan again */ |
68 | 0 | plnr->adt->forget(plnr, FORGET_EVERYTHING); |
69 | |
|
70 | 0 | A(!pln); |
71 | 0 | pln = mkplan0(plnr, flags, prb, hash_info, WISDOM_NORMAL); |
72 | |
|
73 | 0 | if (plnr->wisdom_state == WISDOM_IS_BOGUS) { |
74 | | /* if it still fails, plan without wisdom */ |
75 | 0 | plnr->adt->forget(plnr, FORGET_EVERYTHING); |
76 | |
|
77 | 0 | A(!pln); |
78 | 0 | pln = mkplan0(plnr, force_estimator(flags), |
79 | 0 | prb, hash_info, WISDOM_IGNORE_ALL); |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | 570 | return pln; |
84 | 570 | } |
85 | | |
86 | | apiplan *X(mkapiplan)(int sign, unsigned flags, problem *prb) |
87 | 285 | { |
88 | 285 | apiplan *p = 0; |
89 | 285 | plan *pln; |
90 | 285 | unsigned flags_used_for_planning; |
91 | 285 | planner *plnr; |
92 | 285 | static const unsigned int pats[] = {FFTW_ESTIMATE, FFTW_MEASURE, |
93 | 285 | FFTW_PATIENT, FFTW_EXHAUSTIVE}; |
94 | 285 | int pat, pat_max; |
95 | 285 | double pcost = 0; |
96 | | |
97 | 285 | if (before_planner_hook) |
98 | 0 | before_planner_hook(); |
99 | | |
100 | 285 | plnr = X(the_planner)(); |
101 | | |
102 | 285 | if (flags & FFTW_WISDOM_ONLY) { |
103 | | /* Special mode that returns a plan only if wisdom is present, |
104 | | and returns 0 otherwise. This is now documented in the manual, |
105 | | as a way to detect whether wisdom is available for a problem. */ |
106 | 0 | flags_used_for_planning = flags; |
107 | 0 | pln = mkplan0(plnr, flags, prb, 0, WISDOM_ONLY); |
108 | 285 | } else { |
109 | 285 | pat_max = flags & FFTW_ESTIMATE ? 0 : |
110 | 285 | (flags & FFTW_EXHAUSTIVE ? 3 : |
111 | 0 | (flags & FFTW_PATIENT ? 2 : 1)); |
112 | 285 | pat = plnr->timelimit >= 0 ? 0 : pat_max; |
113 | | |
114 | 285 | flags &= ~(FFTW_ESTIMATE | FFTW_MEASURE | |
115 | 285 | FFTW_PATIENT | FFTW_EXHAUSTIVE); |
116 | | |
117 | 285 | plnr->start_time = X(get_crude_time)(); |
118 | | |
119 | | /* plan at incrementally increasing patience until we run |
120 | | out of time */ |
121 | 570 | for (pln = 0, flags_used_for_planning = 0; pat <= pat_max; ++pat) { |
122 | 285 | plan *pln1; |
123 | 285 | unsigned tmpflags = flags | pats[pat]; |
124 | 285 | pln1 = mkplan(plnr, tmpflags, prb, 0u); |
125 | | |
126 | 285 | if (!pln1) { |
127 | | /* don't bother continuing if planner failed or timed out */ |
128 | 0 | A(!pln || plnr->timed_out); |
129 | 0 | break; |
130 | 0 | } |
131 | | |
132 | 285 | X(plan_destroy_internal)(pln); |
133 | 285 | pln = pln1; |
134 | 285 | flags_used_for_planning = tmpflags; |
135 | 285 | pcost = pln->pcost; |
136 | 285 | } |
137 | 285 | } |
138 | | |
139 | 285 | if (pln) { |
140 | | /* build apiplan */ |
141 | 285 | p = (apiplan *) MALLOC(sizeof(apiplan), PLANS); |
142 | 285 | p->prb = prb; |
143 | 285 | p->refcount = 1u; |
144 | 285 | p->sign = sign; /* cache for execute_dft */ |
145 | | |
146 | | /* re-create plan from wisdom, adding blessing */ |
147 | 285 | p->pln = mkplan(plnr, flags_used_for_planning, prb, BLESSING); |
148 | | |
149 | | /* record pcost from most recent measurement for use in X(cost) */ |
150 | 285 | p->pln->pcost = pcost; |
151 | | |
152 | 285 | if (sizeof(trigreal) > sizeof(R)) { |
153 | | /* this is probably faster, and we have enough trigreal |
154 | | bits to maintain accuracy */ |
155 | 0 | X(plan_awake)(p->pln, AWAKE_SQRTN_TABLE); |
156 | 285 | } else { |
157 | | /* more accurate */ |
158 | 285 | X(plan_awake)(p->pln, AWAKE_SINCOS); |
159 | 285 | } |
160 | | |
161 | | /* we don't use pln for p->pln, above, since by re-creating the |
162 | | plan we might use more patient wisdom from a timed-out mkplan */ |
163 | 285 | X(plan_destroy_internal)(pln); |
164 | 285 | } else |
165 | 0 | X(problem_destroy)(prb); |
166 | | |
167 | | /* discard all information not necessary to reconstruct the plan */ |
168 | 285 | plnr->adt->forget(plnr, FORGET_ACCURSED); |
169 | | |
170 | | #ifdef FFTW_RANDOM_ESTIMATOR |
171 | | X(random_estimate_seed)++; /* subsequent "random" plans are distinct */ |
172 | | #endif |
173 | | |
174 | 285 | if (after_planner_hook) |
175 | 0 | after_planner_hook(); |
176 | | |
177 | 285 | return p; |
178 | 285 | } |
179 | | |
180 | | X(plan) X(copy_plan)(X(plan) p) |
181 | 0 | { |
182 | 0 | if (p) { |
183 | 0 | if (before_planner_hook) |
184 | 0 | before_planner_hook(); |
185 | |
|
186 | 0 | p->refcount++; |
187 | |
|
188 | 0 | if (after_planner_hook) |
189 | 0 | after_planner_hook(); |
190 | 0 | } |
191 | 0 | return p; |
192 | 0 | } |
193 | | |
194 | | void X(destroy_plan)(X(plan) p) |
195 | 285 | { |
196 | 285 | if (p) { |
197 | 285 | if (before_planner_hook) |
198 | 0 | before_planner_hook(); |
199 | | |
200 | 285 | if (p->refcount-- == 1u) { |
201 | 285 | X(plan_awake)(p->pln, SLEEPY); |
202 | 285 | X(plan_destroy_internal)(p->pln); |
203 | 285 | X(problem_destroy)(p->prb); |
204 | 285 | X(ifree)(p); |
205 | 285 | } |
206 | | |
207 | 285 | if (after_planner_hook) |
208 | 0 | after_planner_hook(); |
209 | 285 | } |
210 | 285 | } |
211 | | |
212 | | int X(alignment_of)(R *p) |
213 | 0 | { |
214 | 0 | return X(ialignment_of(p)); |
215 | 0 | } |