|
336
|
1 //============================================================================= |
|
|
2 // |
|
|
3 // mounttime.c |
|
|
4 // |
|
|
5 // Mount timings exerciser, use on a filesystem filled by `makefiles' |
|
|
6 // THIS DOES NOT CURRENTLY WORK ON non-PRO eCos! |
|
|
7 // |
|
|
8 //============================================================================= |
|
|
9 // ####ECOSGPLCOPYRIGHTBEGIN#### |
|
|
10 // ------------------------------------------- |
|
|
11 // This file is part of eCos, the Embedded Configurable Operating System. |
|
|
12 // Copyright (C) 2009 Free Software Foundation, Inc. |
|
|
13 // |
|
|
14 // eCos is free software; you can redistribute it and/or modify it under |
|
|
15 // the terms of the GNU General Public License as published by the Free |
|
|
16 // Software Foundation; either version 2 or (at your option) any later |
|
|
17 // version. |
|
|
18 // |
|
|
19 // eCos is distributed in the hope that it will be useful, but WITHOUT |
|
|
20 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
|
21 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
|
22 // for more details. |
|
|
23 // |
|
|
24 // You should have received a copy of the GNU General Public License |
|
|
25 // along with eCos; if not, write to the Free Software Foundation, Inc., |
|
|
26 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
|
27 // |
|
|
28 // As a special exception, if other files instantiate templates or use |
|
|
29 // macros or inline functions from this file, or you compile this file |
|
|
30 // and link it with other works to produce a work based on this file, |
|
|
31 // this file does not by itself cause the resulting work to be covered by |
|
|
32 // the GNU General Public License. However the source code for this file |
|
|
33 // must still be made available in accordance with section (3) of the GNU |
|
|
34 // General Public License v2. |
|
|
35 // |
|
|
36 // This exception does not invalidate any other reasons why a work based |
|
|
37 // on this file might be covered by the GNU General Public License. |
|
|
38 // ------------------------------------------- |
|
|
39 // ####ECOSGPLCOPYRIGHTEND#### |
|
|
40 //========================================================================== |
|
|
41 //#####DESCRIPTIONBEGIN#### |
|
|
42 // |
|
|
43 // Author(s): wry |
|
|
44 // Date: 2009-06-29 |
|
|
45 // Description: File system mount and unmount timing benchmark. |
|
|
46 // Intended to be used on a complicated filesystem, e.g. |
|
|
47 // one filled up by `makefiles'. |
|
|
48 // Some timing code borrowed from mmfs tests. |
|
|
49 // |
|
|
50 //####DESCRIPTIONEND#### |
|
|
51 //============================================================================= |
|
|
52 |
|
|
53 #include <cyg/infra/testcase.h> |
|
|
54 #include <cyg/infra/diag.h> |
|
|
55 #include <cyg/infra/cyg_ass.h> |
|
|
56 #include <pkgconf/system.h> |
|
|
57 #include <pkgconf/hal.h> |
|
|
58 #include <cyg/hal/hal_intr.h> |
|
|
59 |
|
|
60 #ifndef HAL_CLOCK_READ |
|
|
61 # error "HAL_CLOCK_READ not defined!" |
|
|
62 #endif |
|
|
63 |
|
|
64 #if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) || !defined(CYGPKG_KERNEL) |
|
|
65 |
|
|
66 void cyg_user_start(void) |
|
|
67 { |
|
|
68 CYG_TEST_NA("Needs CYGPKG_KERNEL, CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO"); |
|
|
69 } |
|
|
70 |
|
|
71 #else |
|
|
72 |
|
|
73 #include <cyg/fileio/fileio.h> |
|
|
74 #include <string.h> |
|
|
75 #include <stdio.h> |
|
|
76 #include <unistd.h> |
|
|
77 #include <sys/types.h> |
|
|
78 #include <dirent.h> |
|
|
79 #include <stdlib.h> |
|
|
80 |
|
|
81 #include <cyg/kernel/kapi.h> |
|
|
82 |
|
|
83 #ifdef CYGPKG_DEVS_NAND_SYNTH |
|
|
84 #define DEVICE "synth/0" |
|
|
85 #else |
|
|
86 #define DEVICE "onboard/0" |
|
|
87 #endif |
|
|
88 |
|
|
89 #define MOUNTPOINT "/n" |
|
|
90 #define FSTYPE "yaffs" |
|
|
91 #define _NOCACHE "skip-checkpoint-read" |
|
|
92 |
|
|
93 #define FS_NOCACHE FSTYPE":"_NOCACHE |
|
|
94 |
|
|
95 //#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0) |
|
|
96 |
|
|
97 #define MUST(what) do { \ |
|
|
98 if (0 != what) { \ |
|
|
99 perror(#what); \ |
|
|
100 CYG_TEST_FAIL(#what); \ |
|
|
101 cyg_test_exit(); \ |
|
|
102 } \ |
|
|
103 } while(0) |
|
|
104 |
|
|
105 #define min(a,b) ( (a) > (b) ? (b) : (a) ) |
|
|
106 |
|
|
107 // -------------------------------------------------------------- |
|
|
108 |
|
|
109 void RM_RF_work(const char *f, int recurse) |
|
|
110 { |
|
|
111 MUST(chdir(f)); |
|
|
112 DIR *d = opendir("."); |
|
|
113 if (!d) { |
|
|
114 diag_printf("opendir %s: %s\n", f, strerror(errno)); |
|
|
115 return; |
|
|
116 } |
|
|
117 struct dirent de_stack; |
|
|
118 struct dirent *de_res; |
|
|
119 while (0==readdir_r(d, &de_stack, &de_res) && de_res) { |
|
|
120 struct stat st; |
|
|
121 if (0==strcmp(de_res->d_name,".")) continue; |
|
|
122 if (0==strcmp(de_res->d_name,"..")) continue; |
|
|
123 MUST(stat(de_res->d_name,&st)); |
|
|
124 if (S_ISDIR(st.st_mode)) { |
|
|
125 RM_RF_work(de_res->d_name, recurse+1); |
|
|
126 if (rmdir(de_res->d_name)) |
|
|
127 perror("rmdir"); |
|
|
128 } else { |
|
|
129 MUST(unlink(de_res->d_name)); |
|
|
130 } |
|
|
131 } |
|
|
132 closedir(d); |
|
|
133 MUST(chdir("..")); |
|
|
134 } |
|
|
135 |
|
|
136 void RM_RF(const char *p) |
|
|
137 { |
|
|
138 diag_printf("rm -rf %s\n",p); |
|
|
139 RM_RF_work(p,0); |
|
|
140 MUST(rmdir(p)); |
|
|
141 } |
|
|
142 |
|
|
143 // -------------------------------------------------------------- |
|
|
144 // Timing code cribbed from pvr5.c |
|
|
145 |
|
|
146 typedef struct |
|
|
147 { |
|
|
148 cyg_int64 ticks; |
|
|
149 cyg_uint32 halticks; |
|
|
150 } timestamp; |
|
|
151 |
|
|
152 typedef struct |
|
|
153 { |
|
|
154 timestamp start; |
|
|
155 timestamp end; |
|
|
156 cyg_int64 interval; // In HAL ticks |
|
|
157 cyg_int64 us_interval; // Interval in microseconds |
|
|
158 } timing; |
|
|
159 |
|
|
160 static cyg_int64 ticks_overhead = 0; |
|
|
161 static cyg_int32 us_per_haltick = 0; |
|
|
162 static cyg_int32 halticks_per_us = 0; |
|
|
163 |
|
|
164 static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; |
|
|
165 static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; |
|
|
166 |
|
|
167 static void wait_for_tick( void ) |
|
|
168 { |
|
|
169 cyg_tick_count_t now = cyg_current_time(); |
|
|
170 |
|
|
171 while( cyg_current_time() == now ) |
|
|
172 continue; |
|
|
173 } |
|
|
174 |
|
|
175 static void get_timestamp( timestamp *ts ) |
|
|
176 { |
|
|
177 ts->ticks = cyg_current_time(); |
|
|
178 HAL_CLOCK_READ( &ts->halticks ); |
|
|
179 } |
|
|
180 |
|
|
181 static cyg_int64 ticks_to_us( cyg_int64 ticks ) |
|
|
182 { |
|
|
183 cyg_int64 us; |
|
|
184 |
|
|
185 if( us_per_haltick != 0 ) |
|
|
186 us = ticks * us_per_haltick; |
|
|
187 else |
|
|
188 us = ticks / halticks_per_us; |
|
|
189 |
|
|
190 return us; |
|
|
191 } |
|
|
192 |
|
|
193 static void calculate_interval( timing *t ) |
|
|
194 { |
|
|
195 t->interval = t->end.halticks - t->start.halticks; |
|
|
196 |
|
|
197 t->interval += (t->end.ticks - t->start.ticks) * rtc_period; |
|
|
198 |
|
|
199 t->interval -= ticks_overhead; |
|
|
200 |
|
|
201 t->us_interval = ticks_to_us( t->interval ); |
|
|
202 } |
|
|
203 |
|
|
204 static void init_timing( void ) |
|
|
205 { |
|
|
206 timing t; |
|
|
207 cyg_thread_delay(2); // ensure clock running - asserts if not |
|
|
208 |
|
|
209 us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]); |
|
|
210 halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; |
|
|
211 |
|
|
212 wait_for_tick(); |
|
|
213 |
|
|
214 get_timestamp( &t.start ); |
|
|
215 get_timestamp( &t.end ); |
|
|
216 |
|
|
217 calculate_interval( &t ); |
|
|
218 |
|
|
219 ticks_overhead = t.interval; |
|
|
220 |
|
|
221 diag_printf("Timing overhead %lld ticks (%lluus), this will be factored out of all other measurements\n", ticks_overhead, t.us_interval ); |
|
|
222 } |
|
|
223 |
|
|
224 static timing tm; |
|
|
225 |
|
|
226 #define START() do { \ |
|
|
227 wait_for_tick(); \ |
|
|
228 get_timestamp(&tm.start); \ |
|
|
229 } while(0) |
|
|
230 |
|
|
231 static void report(const char *what, timing tm) |
|
|
232 { |
|
|
233 if (tm.us_interval > 1100000) |
|
|
234 diag_printf("%30s: %2d.%03d s\n", what, (int)(tm.us_interval/1000000), (int)(tm.us_interval/1000)%1000); |
|
|
235 else |
|
|
236 diag_printf("%30s: %2d.%03d ms\n", what, (int)(tm.us_interval/1000), (int)(tm.us_interval%1000)); |
|
|
237 |
|
|
238 } |
|
|
239 |
|
|
240 #define STOP(what) do { \ |
|
|
241 get_timestamp(&tm.end); \ |
|
|
242 calculate_interval(&tm); \ |
|
|
243 report(what, tm); \ |
|
|
244 } while(0) |
|
|
245 |
|
|
246 // -------------------------------------------------------------- |
|
|
247 |
|
|
248 void dumpmallinfo(void) |
|
|
249 { |
|
|
250 struct mallinfo mi = mallinfo(); |
|
|
251 int total_ord = mi.uordblks + mi.fordblks; |
|
|
252 double pct = (double)mi.uordblks / (double)total_ord; |
|
|
253 diag_printf("! Arena: size 0x%x, small blks %u/%u, ord blks used %u/%u (%u%%)\n", |
|
|
254 mi.arena, |
|
|
255 mi.usmblks, mi.fsmblks, |
|
|
256 mi.uordblks, total_ord, (int)(100.0*pct)); |
|
|
257 } |
|
|
258 |
|
|
259 // -------------------------------------------------------------- |
|
|
260 |
|
|
261 #define WORKDIR MOUNTPOINT "/" "test" |
|
|
262 |
|
|
263 void mounttime_main(void) |
|
|
264 { |
|
|
265 #define NTIMES 3 |
|
|
266 int i; |
|
|
267 for (i=0; i<NTIMES; i++) { |
|
|
268 START(); |
|
|
269 MUST(mount(DEVICE, MOUNTPOINT, FSTYPE)); |
|
|
270 STOP("remount"); |
|
|
271 //if (i==0) dumpmallinfo(); |
|
|
272 START(); |
|
|
273 MUST(umount(MOUNTPOINT)); |
|
|
274 STOP("unmount"); |
|
|
275 |
|
|
276 START(); |
|
|
277 MUST(mount(DEVICE, MOUNTPOINT, FS_NOCACHE)); |
|
|
278 // plain eCos does not support mount options, this test won't work there. |
|
|
279 STOP("remount without checkpoint"); |
|
|
280 //if (i==0) dumpmallinfo(); |
|
|
281 START(); |
|
|
282 MUST(umount(MOUNTPOINT)); |
|
|
283 STOP("unmount"); |
|
|
284 //if (i==0) dumpmallinfo(); |
|
|
285 } |
|
|
286 //dumpmallinfo(); |
|
|
287 |
|
|
288 // then consider repeats.. |
|
|
289 |
|
|
290 CYG_TEST_EXIT("Run complete"); |
|
|
291 } |
|
|
292 |
|
|
293 int main(void) |
|
|
294 { |
|
|
295 CYG_TEST_INIT(); |
|
|
296 init_timing(); |
|
|
297 |
|
|
298 mounttime_main(); |
|
|
299 return 0; |
|
|
300 } |
|
|
301 |
|
|
302 #endif |
|
|
303 |