cannam@167
|
1 /*
|
cannam@167
|
2 * Copyright (c) 2001 Matteo Frigo
|
cannam@167
|
3 * Copyright (c) 2001 Massachusetts Institute of Technology
|
cannam@167
|
4 *
|
cannam@167
|
5 * This program is free software; you can redistribute it and/or modify
|
cannam@167
|
6 * it under the terms of the GNU General Public License as published by
|
cannam@167
|
7 * the Free Software Foundation; either version 2 of the License, or
|
cannam@167
|
8 * (at your option) any later version.
|
cannam@167
|
9 *
|
cannam@167
|
10 * This program is distributed in the hope that it will be useful,
|
cannam@167
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
cannam@167
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
cannam@167
|
13 * GNU General Public License for more details.
|
cannam@167
|
14 *
|
cannam@167
|
15 * You should have received a copy of the GNU General Public License
|
cannam@167
|
16 * along with this program; if not, write to the Free Software
|
cannam@167
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
cannam@167
|
18 *
|
cannam@167
|
19 */
|
cannam@167
|
20
|
cannam@167
|
21 #include "libbench2/bench.h"
|
cannam@167
|
22 #include <stdlib.h>
|
cannam@167
|
23
|
cannam@167
|
24 bench_tensor *mktensor(int rnk)
|
cannam@167
|
25 {
|
cannam@167
|
26 bench_tensor *x;
|
cannam@167
|
27
|
cannam@167
|
28 BENCH_ASSERT(rnk >= 0);
|
cannam@167
|
29
|
cannam@167
|
30 x = (bench_tensor *)bench_malloc(sizeof(bench_tensor));
|
cannam@167
|
31 if (BENCH_FINITE_RNK(rnk) && rnk > 0)
|
cannam@167
|
32 x->dims = (bench_iodim *)bench_malloc(sizeof(bench_iodim) * rnk);
|
cannam@167
|
33 else
|
cannam@167
|
34 x->dims = 0;
|
cannam@167
|
35
|
cannam@167
|
36 x->rnk = rnk;
|
cannam@167
|
37 return x;
|
cannam@167
|
38 }
|
cannam@167
|
39
|
cannam@167
|
40 void tensor_destroy(bench_tensor *sz)
|
cannam@167
|
41 {
|
cannam@167
|
42 bench_free0(sz->dims);
|
cannam@167
|
43 bench_free(sz);
|
cannam@167
|
44 }
|
cannam@167
|
45
|
cannam@167
|
46 size_t tensor_sz(const bench_tensor *sz)
|
cannam@167
|
47 {
|
cannam@167
|
48 int i;
|
cannam@167
|
49 size_t n = 1;
|
cannam@167
|
50
|
cannam@167
|
51 if (!BENCH_FINITE_RNK(sz->rnk))
|
cannam@167
|
52 return 0;
|
cannam@167
|
53
|
cannam@167
|
54 for (i = 0; i < sz->rnk; ++i)
|
cannam@167
|
55 n *= sz->dims[i].n;
|
cannam@167
|
56 return n;
|
cannam@167
|
57 }
|
cannam@167
|
58
|
cannam@167
|
59
|
cannam@167
|
60 /* total order among bench_iodim's */
|
cannam@167
|
61 static int dimcmp(const bench_iodim *a, const bench_iodim *b)
|
cannam@167
|
62 {
|
cannam@167
|
63 if (b->is != a->is)
|
cannam@167
|
64 return (b->is - a->is); /* shorter strides go later */
|
cannam@167
|
65 if (b->os != a->os)
|
cannam@167
|
66 return (b->os - a->os); /* shorter strides go later */
|
cannam@167
|
67 return (int)(a->n - b->n); /* larger n's go later */
|
cannam@167
|
68 }
|
cannam@167
|
69
|
cannam@167
|
70 bench_tensor *tensor_compress(const bench_tensor *sz)
|
cannam@167
|
71 {
|
cannam@167
|
72 int i, rnk;
|
cannam@167
|
73 bench_tensor *x;
|
cannam@167
|
74
|
cannam@167
|
75 BENCH_ASSERT(BENCH_FINITE_RNK(sz->rnk));
|
cannam@167
|
76 for (i = rnk = 0; i < sz->rnk; ++i) {
|
cannam@167
|
77 BENCH_ASSERT(sz->dims[i].n > 0);
|
cannam@167
|
78 if (sz->dims[i].n != 1)
|
cannam@167
|
79 ++rnk;
|
cannam@167
|
80 }
|
cannam@167
|
81
|
cannam@167
|
82 x = mktensor(rnk);
|
cannam@167
|
83 for (i = rnk = 0; i < sz->rnk; ++i) {
|
cannam@167
|
84 if (sz->dims[i].n != 1)
|
cannam@167
|
85 x->dims[rnk++] = sz->dims[i];
|
cannam@167
|
86 }
|
cannam@167
|
87
|
cannam@167
|
88 if (rnk) {
|
cannam@167
|
89 /* God knows how qsort() behaves if n==0 */
|
cannam@167
|
90 qsort(x->dims, (size_t)x->rnk, sizeof(bench_iodim),
|
cannam@167
|
91 (int (*)(const void *, const void *))dimcmp);
|
cannam@167
|
92 }
|
cannam@167
|
93
|
cannam@167
|
94 return x;
|
cannam@167
|
95 }
|
cannam@167
|
96
|
cannam@167
|
97 int tensor_unitstridep(bench_tensor *t)
|
cannam@167
|
98 {
|
cannam@167
|
99 BENCH_ASSERT(BENCH_FINITE_RNK(t->rnk));
|
cannam@167
|
100 return (t->rnk == 0 ||
|
cannam@167
|
101 (t->dims[t->rnk - 1].is == 1 && t->dims[t->rnk - 1].os == 1));
|
cannam@167
|
102 }
|
cannam@167
|
103
|
cannam@167
|
104 /* detect screwy real padded rowmajor... ugh */
|
cannam@167
|
105 int tensor_real_rowmajorp(bench_tensor *t, int sign, int in_place)
|
cannam@167
|
106 {
|
cannam@167
|
107 int i;
|
cannam@167
|
108
|
cannam@167
|
109 BENCH_ASSERT(BENCH_FINITE_RNK(t->rnk));
|
cannam@167
|
110
|
cannam@167
|
111 i = t->rnk - 1;
|
cannam@167
|
112
|
cannam@167
|
113 if (--i >= 0) {
|
cannam@167
|
114 bench_iodim *d = t->dims + i;
|
cannam@167
|
115 if (sign < 0) {
|
cannam@167
|
116 if (d[0].is != d[1].is * (in_place ? 2*(d[1].n/2 + 1) : d[1].n))
|
cannam@167
|
117 return 0;
|
cannam@167
|
118 if (d[0].os != d[1].os * (d[1].n/2 + 1))
|
cannam@167
|
119 return 0;
|
cannam@167
|
120 }
|
cannam@167
|
121 else {
|
cannam@167
|
122 if (d[0].is != d[1].is * (d[1].n/2 + 1))
|
cannam@167
|
123 return 0;
|
cannam@167
|
124 if (d[0].os != d[1].os * (in_place ? 2*(d[1].n/2 + 1) : d[1].n))
|
cannam@167
|
125 return 0;
|
cannam@167
|
126 }
|
cannam@167
|
127 }
|
cannam@167
|
128
|
cannam@167
|
129 while (--i >= 0) {
|
cannam@167
|
130 bench_iodim *d = t->dims + i;
|
cannam@167
|
131 if (d[0].is != d[1].is * d[1].n)
|
cannam@167
|
132 return 0;
|
cannam@167
|
133 if (d[0].os != d[1].os * d[1].n)
|
cannam@167
|
134 return 0;
|
cannam@167
|
135 }
|
cannam@167
|
136 return 1;
|
cannam@167
|
137 }
|
cannam@167
|
138
|
cannam@167
|
139 int tensor_rowmajorp(bench_tensor *t)
|
cannam@167
|
140 {
|
cannam@167
|
141 int i;
|
cannam@167
|
142
|
cannam@167
|
143 BENCH_ASSERT(BENCH_FINITE_RNK(t->rnk));
|
cannam@167
|
144
|
cannam@167
|
145 i = t->rnk - 1;
|
cannam@167
|
146 while (--i >= 0) {
|
cannam@167
|
147 bench_iodim *d = t->dims + i;
|
cannam@167
|
148 if (d[0].is != d[1].is * d[1].n)
|
cannam@167
|
149 return 0;
|
cannam@167
|
150 if (d[0].os != d[1].os * d[1].n)
|
cannam@167
|
151 return 0;
|
cannam@167
|
152 }
|
cannam@167
|
153 return 1;
|
cannam@167
|
154 }
|
cannam@167
|
155
|
cannam@167
|
156 static void dimcpy(bench_iodim *dst, const bench_iodim *src, int rnk)
|
cannam@167
|
157 {
|
cannam@167
|
158 int i;
|
cannam@167
|
159 if (BENCH_FINITE_RNK(rnk))
|
cannam@167
|
160 for (i = 0; i < rnk; ++i)
|
cannam@167
|
161 dst[i] = src[i];
|
cannam@167
|
162 }
|
cannam@167
|
163
|
cannam@167
|
164 bench_tensor *tensor_append(const bench_tensor *a, const bench_tensor *b)
|
cannam@167
|
165 {
|
cannam@167
|
166 if (!BENCH_FINITE_RNK(a->rnk) || !BENCH_FINITE_RNK(b->rnk)) {
|
cannam@167
|
167 return mktensor(BENCH_RNK_MINFTY);
|
cannam@167
|
168 } else {
|
cannam@167
|
169 bench_tensor *x = mktensor(a->rnk + b->rnk);
|
cannam@167
|
170 dimcpy(x->dims, a->dims, a->rnk);
|
cannam@167
|
171 dimcpy(x->dims + a->rnk, b->dims, b->rnk);
|
cannam@167
|
172 return x;
|
cannam@167
|
173 }
|
cannam@167
|
174 }
|
cannam@167
|
175
|
cannam@167
|
176 static int imax(int a, int b)
|
cannam@167
|
177 {
|
cannam@167
|
178 return (a > b) ? a : b;
|
cannam@167
|
179 }
|
cannam@167
|
180
|
cannam@167
|
181 static int imin(int a, int b)
|
cannam@167
|
182 {
|
cannam@167
|
183 return (a < b) ? a : b;
|
cannam@167
|
184 }
|
cannam@167
|
185
|
cannam@167
|
186 #define DEFBOUNDS(name, xs) \
|
cannam@167
|
187 void name(bench_tensor *t, int *lbp, int *ubp) \
|
cannam@167
|
188 { \
|
cannam@167
|
189 int lb = 0; \
|
cannam@167
|
190 int ub = 1; \
|
cannam@167
|
191 int i; \
|
cannam@167
|
192 \
|
cannam@167
|
193 BENCH_ASSERT(BENCH_FINITE_RNK(t->rnk)); \
|
cannam@167
|
194 \
|
cannam@167
|
195 for (i = 0; i < t->rnk; ++i) { \
|
cannam@167
|
196 bench_iodim *d = t->dims + i; \
|
cannam@167
|
197 int n = d->n; \
|
cannam@167
|
198 int s = d->xs; \
|
cannam@167
|
199 lb = imin(lb, lb + s * (n - 1)); \
|
cannam@167
|
200 ub = imax(ub, ub + s * (n - 1)); \
|
cannam@167
|
201 } \
|
cannam@167
|
202 \
|
cannam@167
|
203 *lbp = lb; \
|
cannam@167
|
204 *ubp = ub; \
|
cannam@167
|
205 }
|
cannam@167
|
206
|
cannam@167
|
207 DEFBOUNDS(tensor_ibounds, is)
|
cannam@167
|
208 DEFBOUNDS(tensor_obounds, os)
|
cannam@167
|
209
|
cannam@167
|
210 bench_tensor *tensor_copy(const bench_tensor *sz)
|
cannam@167
|
211 {
|
cannam@167
|
212 bench_tensor *x = mktensor(sz->rnk);
|
cannam@167
|
213 dimcpy(x->dims, sz->dims, sz->rnk);
|
cannam@167
|
214 return x;
|
cannam@167
|
215 }
|
cannam@167
|
216
|
cannam@167
|
217 /* Like tensor_copy, but copy only rnk dimensions starting with start_dim. */
|
cannam@167
|
218 bench_tensor *tensor_copy_sub(const bench_tensor *sz, int start_dim, int rnk)
|
cannam@167
|
219 {
|
cannam@167
|
220 bench_tensor *x;
|
cannam@167
|
221
|
cannam@167
|
222 BENCH_ASSERT(BENCH_FINITE_RNK(sz->rnk) && start_dim + rnk <= sz->rnk);
|
cannam@167
|
223 x = mktensor(rnk);
|
cannam@167
|
224 dimcpy(x->dims, sz->dims + start_dim, rnk);
|
cannam@167
|
225 return x;
|
cannam@167
|
226 }
|
cannam@167
|
227
|
cannam@167
|
228 bench_tensor *tensor_copy_swapio(const bench_tensor *sz)
|
cannam@167
|
229 {
|
cannam@167
|
230 bench_tensor *x = tensor_copy(sz);
|
cannam@167
|
231 int i;
|
cannam@167
|
232 if (BENCH_FINITE_RNK(x->rnk))
|
cannam@167
|
233 for (i = 0; i < x->rnk; ++i) {
|
cannam@167
|
234 int s;
|
cannam@167
|
235 s = x->dims[i].is;
|
cannam@167
|
236 x->dims[i].is = x->dims[i].os;
|
cannam@167
|
237 x->dims[i].os = s;
|
cannam@167
|
238 }
|
cannam@167
|
239 return x;
|
cannam@167
|
240 }
|