Mercurial > nand-ecoscentric
annotate packages/io/nand/current/tests/nand_rwbenchmark.c @ 3394:7905ed422fdf
io/nand: Rename CYGINT_IO_NAND_TEST_PARTITION to CYGNUM_IO_NAND_TEST_PARTITION.
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Tue, 02 Dec 2014 12:07:18 +1300 |
| parents | c1cbf062a826 |
| children |
| rev | line source |
|---|---|
| 3017 | 1 //============================================================================= |
| 2 // | |
| 3 // mounttime.c | |
| 4 // | |
| 5 // Mount timings exerciser, use on a filesystem filled by `makefiles' | |
| 6 // | |
| 7 //============================================================================= | |
| 8 // ####ECOSGPLCOPYRIGHTBEGIN#### | |
| 9 // ------------------------------------------- | |
| 10 // This file is part of eCos, the Embedded Configurable Operating System. | |
| 11 // Copyright (C) 2009 Free Software Foundation, Inc. | |
| 12 // | |
| 13 // eCos is free software; you can redistribute it and/or modify it under | |
| 14 // the terms of the GNU General Public License as published by the Free | |
| 15 // Software Foundation; either version 2 or (at your option) any later | |
| 16 // version. | |
| 17 // | |
| 18 // eCos is distributed in the hope that it will be useful, but WITHOUT | |
| 19 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 21 // for more details. | |
| 22 // | |
| 23 // You should have received a copy of the GNU General Public License | |
| 24 // along with eCos; if not, write to the Free Software Foundation, Inc., | |
| 25 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
| 26 // | |
| 27 // As a special exception, if other files instantiate templates or use | |
| 28 // macros or inline functions from this file, or you compile this file | |
| 29 // and link it with other works to produce a work based on this file, | |
| 30 // this file does not by itself cause the resulting work to be covered by | |
| 31 // the GNU General Public License. However the source code for this file | |
| 32 // must still be made available in accordance with section (3) of the GNU | |
| 33 // General Public License v2. | |
| 34 // | |
| 35 // This exception does not invalidate any other reasons why a work based | |
| 36 // on this file might be covered by the GNU General Public License. | |
| 37 // ------------------------------------------- | |
| 38 // ####ECOSGPLCOPYRIGHTEND#### | |
| 39 //========================================================================== | |
| 40 //#####DESCRIPTIONBEGIN#### | |
| 41 // | |
| 42 // Author(s): wry | |
| 43 // Date: 2009-07-02 | |
| 44 // Description: Read, write and erase timing benchmark. | |
| 45 // Some timing code borrowed from mmfs tests. | |
| 46 // | |
| 47 //####DESCRIPTIONEND#### | |
| 48 //============================================================================= | |
| 49 | |
| 50 #include <cyg/infra/testcase.h> | |
| 51 #include <cyg/infra/diag.h> | |
| 52 #include <cyg/infra/cyg_ass.h> | |
| 53 #include <pkgconf/system.h> | |
| 54 #include <pkgconf/hal.h> | |
| 55 #include <cyg/hal/hal_intr.h> | |
| 56 | |
| 57 #ifndef HAL_CLOCK_READ | |
| 58 # error "HAL_CLOCK_READ not defined!" | |
| 59 #endif | |
| 60 | |
| 61 #if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) || !defined(CYGPKG_KERNEL) | |
| 62 | |
| 63 void cyg_user_start(void) | |
| 64 { | |
|
3379
b1e9145ae7cd
packages/io/nand/current/tests/nand_rwbenchmark.c: Add CYG_TEST_INIT() before CYG_TEST_NA() to allow auto-testing cyg_test_init() breakpoint to work.
James G. Smith <jsmith@ecoscentric.com>
parents:
3017
diff
changeset
|
65 CYG_TEST_INIT(); |
| 3017 | 66 CYG_TEST_NA("Needs CYGPKG_KERNEL, CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO"); |
| 67 } | |
| 68 | |
| 69 #else | |
| 70 | |
| 71 #include <cyg/nand/nand.h> | |
| 72 #include <cyg/nand/nand_device.h> | |
| 73 #include <cyg/nand/util.h> | |
| 74 | |
| 75 #include <string.h> | |
| 76 #include <stdio.h> | |
| 77 #include <unistd.h> | |
| 78 #include <sys/types.h> | |
| 79 #include <dirent.h> | |
| 80 #include <stdlib.h> | |
| 81 | |
| 82 #include <cyg/kernel/kapi.h> | |
| 83 | |
| 84 #include "ar4prng.inl" | |
| 85 ar4ctx rnd; | |
| 86 /* we'll use our text segment as seed to the prng; not crypto-secure but | |
| 87 * pretty good for running tests */ | |
| 88 extern unsigned char _stext[], _etext[]; | |
| 89 | |
| 90 | |
| 91 #ifdef CYGPKG_DEVS_NAND_SYNTH | |
| 92 #define DEVICE "synth" | |
| 93 #else | |
| 94 #define DEVICE "onboard" | |
| 95 #endif | |
| 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 // Timing code cribbed from pvr5.c | |
| 109 | |
| 110 typedef struct | |
| 111 { | |
| 112 cyg_int64 ticks; | |
| 113 cyg_uint32 halticks; | |
| 114 } timestamp; | |
| 115 | |
| 116 typedef struct | |
| 117 { | |
| 118 timestamp start; | |
| 119 timestamp end; | |
| 120 cyg_int64 interval; // In HAL ticks | |
| 121 cyg_int64 us_interval; // Interval in microseconds | |
| 122 } timing; | |
| 123 | |
| 124 static cyg_int64 ticks_overhead = 0; | |
| 125 static cyg_int32 us_per_haltick = 0; | |
| 126 static cyg_int32 halticks_per_us = 0; | |
| 127 | |
| 128 static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; | |
|
3385
631d86e5d620
io/nand tests/nand_rwbenchmark.c: Cope with CYGNUM_KERNEL_COUNTERS_RTC_PERIOD not being constant.
Ross Younger <wry@ecoscentric.com>
parents:
3383
diff
changeset
|
129 static cyg_int64 rtc_period; |
| 3017 | 130 |
| 131 static void wait_for_tick( void ) | |
| 132 { | |
| 133 cyg_tick_count_t now = cyg_current_time(); | |
| 134 | |
| 135 while( cyg_current_time() == now ) | |
| 136 continue; | |
| 137 } | |
| 138 | |
| 139 static void get_timestamp( timestamp *ts ) | |
| 140 { | |
| 141 ts->ticks = cyg_current_time(); | |
| 142 HAL_CLOCK_READ( &ts->halticks ); | |
| 143 } | |
| 144 | |
| 145 static cyg_int64 ticks_to_us( cyg_int64 ticks ) | |
| 146 { | |
| 147 cyg_int64 us; | |
| 148 | |
| 149 if( us_per_haltick != 0 ) | |
| 150 us = ticks * us_per_haltick; | |
| 151 else | |
| 152 us = ticks / halticks_per_us; | |
| 153 | |
| 154 return us; | |
| 155 } | |
| 156 | |
| 157 static void calculate_interval( timing *t ) | |
| 158 { | |
| 159 t->interval = t->end.halticks - t->start.halticks; | |
| 160 | |
| 161 t->interval += (t->end.ticks - t->start.ticks) * rtc_period; | |
| 162 | |
| 163 t->interval -= ticks_overhead; | |
| 164 | |
| 165 t->us_interval = ticks_to_us( t->interval ); | |
| 166 } | |
| 167 | |
| 168 static void init_timing( void ) | |
| 169 { | |
| 170 timing t; | |
| 171 | |
| 172 cyg_thread_delay(2); // ensure clock running - asserts if not | |
| 173 | |
|
3385
631d86e5d620
io/nand tests/nand_rwbenchmark.c: Cope with CYGNUM_KERNEL_COUNTERS_RTC_PERIOD not being constant.
Ross Younger <wry@ecoscentric.com>
parents:
3383
diff
changeset
|
174 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; |
| 3017 | 175 us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]); |
| 176 halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; | |
| 177 | |
| 178 wait_for_tick(); | |
| 179 | |
| 180 get_timestamp( &t.start ); | |
| 181 get_timestamp( &t.end ); | |
| 182 | |
| 183 calculate_interval( &t ); | |
| 184 | |
| 185 ticks_overhead = t.interval; | |
| 186 | |
| 187 diag_printf("Timing overhead %lld ticks (%lluus), this will be factored out of all other measurements\n", ticks_overhead, t.us_interval ); | |
| 188 } | |
| 189 | |
| 190 #define disable_clock_latency_measurement() | |
| 191 #define enable_clock_latency_measurement() | |
| 192 | |
| 193 // -------------------------------------------------------------- | |
| 194 | |
| 195 void | |
| 196 show_times_hdr(void) | |
| 197 { | |
| 198 disable_clock_latency_measurement(); | |
| 199 diag_printf("\n"); | |
| 200 #ifdef _TM_BASIC_HAL_CLOCK_READ_UNDEFINED | |
| 201 diag_printf("HAL_CLOCK_READ() is not supported on this platform.\n"); | |
| 202 diag_printf("Timing results are meaningless.\n"); | |
| 203 #endif | |
| 204 diag_printf("All times are in microseconds (us) unless stated\n"); | |
| 205 diag_printf("\n"); | |
| 206 diag_printf(" Confidence\n"); | |
| 207 diag_printf(" Ave Min Max Var Ave Min Function\n"); | |
| 208 diag_printf(" ====== ====== ====== ====== ========== ========\n"); | |
| 209 enable_clock_latency_measurement(); | |
| 210 } | |
| 211 | |
| 212 // Display a time result | |
| 213 void | |
| 214 show_ns(cyg_uint64 ns) | |
| 215 { | |
| 216 if (ns > 999995000) { | |
| 217 ns += 5000000; // round to nearest 0.01s | |
| 218 diag_printf("%5u.%02us", (int)(ns/1000000000), (int)((ns%1000000000)/10000000)); | |
| 219 | |
| 220 } else if (ns >= 99999995) { | |
| 221 ns += 5000; // round to 0.01ms | |
| 222 diag_printf("%4u.%02ums", (int)(ns/1000000), (int)((ns%1000000)/10000)); | |
| 223 } else { | |
| 224 ns += 5; // round to .01us | |
| 225 diag_printf("%6u.%02u", (int)(ns/1000), (int)((ns%1000)/10)); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 void | |
| 230 show_times_detail(timing ft[], int nsamples, char *title, bool ignore_first) | |
| 231 { | |
| 232 int i; | |
| 233 int start_sample, total_samples; | |
| 234 cyg_uint64 delta, total, ave, min, max, ave_dev; | |
| 235 /* we measure in ticks, convert to us, but store as ns for good precision */ | |
| 236 cyg_int32 con_ave, con_min; | |
| 237 | |
| 238 if (ignore_first) { | |
| 239 start_sample = 1; | |
| 240 total_samples = nsamples-1; | |
| 241 } else { | |
| 242 start_sample = 0; | |
| 243 total_samples = nsamples; | |
| 244 } | |
| 245 | |
| 246 total = 0; | |
| 247 min = 0xFFFFffffFFFFffffULL; | |
| 248 max = 0; | |
| 249 for (i = start_sample; i < nsamples; i++) { | |
| 250 calculate_interval(&ft[i]); | |
| 251 delta = ft[i].us_interval * 1000; | |
| 252 total += delta; | |
| 253 if (delta < min) min = delta; | |
| 254 if (delta > max) max = delta; | |
| 255 } | |
| 256 ave = total / total_samples; | |
| 257 | |
| 258 ave_dev = 0; | |
| 259 for (i = start_sample; i < nsamples; i++) { | |
| 260 delta = ft[i].us_interval * 1000; | |
| 261 if (delta > ave) | |
| 262 delta = delta - ave; | |
| 263 else | |
| 264 delta = ave - delta; | |
| 265 ave_dev += delta; | |
| 266 } | |
| 267 ave_dev /= total_samples; | |
| 268 | |
| 269 con_ave = 0; | |
| 270 con_min = 0; | |
| 271 for (i = start_sample; i < nsamples; i++) { | |
| 272 delta = ft[i].us_interval * 1000; | |
| 273 if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++; | |
| 274 if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++; | |
| 275 } | |
| 276 con_ave = (con_ave * 100) / total_samples; | |
| 277 con_min = (con_min * 100) / total_samples; | |
| 278 | |
| 279 disable_clock_latency_measurement(); | |
| 280 show_ns(ave); | |
| 281 show_ns(min); | |
| 282 show_ns(max); | |
| 283 show_ns(ave_dev); | |
| 284 diag_printf(" %3d%% %3d%%", con_ave, con_min); | |
| 285 diag_printf(" %s\n", title); | |
| 286 | |
| 287 CYG_ASSERT( ave <= max, "ave < max" ); | |
| 288 | |
| 289 enable_clock_latency_measurement(); | |
| 290 } | |
| 291 | |
| 292 void | |
| 293 show_times(timing ft[], int nsamples, char *title) | |
| 294 { | |
| 295 show_times_detail(ft, nsamples, title, false); | |
| 296 #ifdef STATS_WITHOUT_FIRST_SAMPLE | |
| 297 show_times_detail(ft, nsamples, "", true); | |
| 298 #endif | |
| 299 } | |
| 300 | |
| 301 // -------------------------------------------------------------- | |
| 302 | |
| 303 #define WORKDIR MOUNTPOINT "/" "test" | |
| 304 | |
| 305 #define NREADS 100 | |
| 306 #define NBULKREADS 10 | |
| 307 #define NBULKWRITES 10 | |
| 308 #define NWRITES 30 | |
| 309 #define NERASES 30 | |
| 310 | |
| 311 void show_test_parameters(cyg_nand_device *dev) | |
| 312 { | |
| 313 disable_clock_latency_measurement(); | |
| 314 diag_printf("\nTesting parameters:\n"); | |
| 315 diag_printf(" NAND reads: %5u\n", NREADS); | |
| 316 if (NWRITES) | |
| 317 diag_printf(" NAND writes: %5u\n", NWRITES); | |
| 318 if (NERASES) | |
| 319 diag_printf(" NAND erases: %5u\n", NERASES); | |
| 320 if (NBULKREADS) | |
| 321 diag_printf(" NAND bulk reads: %5u\n", NBULKREADS); | |
| 322 if (NBULKWRITES) | |
| 323 diag_printf(" NAND bulk writes: %5u\n", NBULKWRITES); | |
| 324 diag_printf(" Device page size: %5u bytes\n" | |
| 325 " Device block size: %5u pages\n", | |
| 326 CYG_NAND_BYTES_PER_PAGE(dev), | |
| 327 CYG_NAND_PAGES_PER_BLOCK(dev) ); | |
| 328 | |
| 329 enable_clock_latency_measurement(); | |
| 330 } | |
| 331 | |
| 332 cyg_nand_block_addr find_spare_block(cyg_nand_partition *part) | |
| 333 { | |
| 334 const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); | |
| 335 unsigned char oob[oobz]; | |
| 336 int i,rv; | |
| 337 cyg_nand_block_addr b; | |
| 338 | |
|
3383
060772fa9bb3
nand tests/nand_rwbenchmark.c: Fix infinite loop when all blocks are marked bad.
Ross Younger <wry@ecoscentric.com>
parents:
3379
diff
changeset
|
339 for (b=CYG_NAND_PARTITION_NBLOCKS(part)-1; b>=1; b--) { |
|
060772fa9bb3
nand tests/nand_rwbenchmark.c: Fix infinite loop when all blocks are marked bad.
Ross Younger <wry@ecoscentric.com>
parents:
3379
diff
changeset
|
340 /* Testing for b>=1 means we don't check block 0 for |
|
060772fa9bb3
nand tests/nand_rwbenchmark.c: Fix infinite loop when all blocks are marked bad.
Ross Younger <wry@ecoscentric.com>
parents:
3379
diff
changeset
|
341 * availability, but if we get there then realistically |
|
060772fa9bb3
nand tests/nand_rwbenchmark.c: Fix infinite loop when all blocks are marked bad.
Ross Younger <wry@ecoscentric.com>
parents:
3379
diff
changeset
|
342 * the device is worn out anyway. So fail the test. */ |
| 3017 | 343 cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, b); |
| 344 rv = cyg_nandp_read_page(part, pg, 0, oob, oobz); | |
| 345 if (rv != 0) continue; // bad block? | |
| 346 | |
| 347 for (i=0; i<oobz; i++) | |
| 348 if (oob[i] != 0xff) | |
| 349 goto next; | |
| 350 | |
| 351 // oob all FF: take it! | |
| 352 return b; | |
| 353 next: | |
| 354 ; | |
| 355 } | |
| 356 | |
|
3383
060772fa9bb3
nand tests/nand_rwbenchmark.c: Fix infinite loop when all blocks are marked bad.
Ross Younger <wry@ecoscentric.com>
parents:
3379
diff
changeset
|
357 CYG_TEST_FAIL_EXIT("can't find an untagged block - device worn out?"); |
| 3017 | 358 } |
| 359 | |
| 360 CYG_BYTE databuf[CYGNUM_NAND_PAGEBUFFER], testbuf[CYGNUM_NAND_PAGEBUFFER]; | |
| 361 timing ft_read[NREADS]; | |
| 362 timing ft_write[NWRITES]; | |
| 363 timing ft_erase[NERASES]; | |
| 364 timing ft_bulkread[NBULKREADS]; | |
| 365 timing ft_bulkwrite[NBULKWRITES]; | |
| 366 | |
| 367 int fails = 0; | |
| 368 | |
| 369 void test_reads(cyg_nand_partition *part, cyg_nand_block_addr b) | |
| 370 { | |
| 371 cyg_nand_page_addr pgstart = CYG_NAND_BLOCK2PAGEADDR(part->dev, b), | |
| 372 pgend = CYG_NAND_BLOCK2PAGEADDR(part->dev, b+1)-1, | |
| 373 pg = pgstart; | |
| 374 int i, rv; | |
| 375 const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); | |
| 376 unsigned char oob[oobz]; | |
| 377 #define ft ft_read | |
| 378 | |
| 379 /* First, set up the block the way we want it ... */ | |
| 380 cyg_nandp_erase_block(part, b); | |
| 381 memcpy(oob, databuf, oobz); | |
| 382 for (i=pgstart; i <= pgend; i++) { | |
| 383 rv = cyg_nandp_write_page(part, i, databuf, oob, oobz); | |
| 384 switch (rv) { | |
| 385 case 0: break; | |
| 386 case -EIO: | |
| 387 cyg_nandp_bbt_markbad(part, b); | |
| 388 CYG_TEST_FAIL_FINISH("Write failed; block now marked as bad. This run can't continue but should be OK to repeat."); | |
| 389 | |
| 390 default: | |
| 391 diag_printf("Unexpected write failure: %d\n", rv); | |
| 392 CYG_TEST_FAIL_FINISH("Pre-write failed"); | |
| 393 } | |
| 394 } | |
| 395 | |
| 396 #define CLEARDATA() memset(testbuf, 0, sizeof testbuf) | |
| 397 #define CHECKDATA() do { if (0 != memcmp(testbuf, databuf, sizeof testbuf)) { \ | |
| 398 CYG_TEST_FAIL("readback check failed"); \ | |
| 399 ++fails; \ | |
| 400 break; \ | |
| 401 } } while(0) | |
| 402 | |
| 403 #define CLEAROOB() memset(oob, 0, oobz) | |
| 404 #define CHECKOOB() do { if (0 != memcmp(oob, databuf, oobz)) { \ | |
| 405 CYG_TEST_FAIL("readback OOB check failed"); \ | |
| 406 ++fails; \ | |
| 407 break; \ | |
| 408 } } while(0) | |
| 409 | |
| 410 | |
| 411 for (i=0; i < NREADS; i++) { | |
| 412 CLEARDATA(); | |
| 413 wait_for_tick(); | |
| 414 get_timestamp(&ft[i].start); | |
| 415 cyg_nandp_read_page(part, pg, testbuf, 0, 0); | |
| 416 get_timestamp(&ft[i].end); | |
| 417 CHECKDATA(); | |
| 418 ++pg; | |
| 419 if (pg > pgend) pg = pgstart; | |
| 420 } | |
| 421 show_times(ft, NREADS, "NAND page reads (page data only)"); | |
| 422 | |
| 423 for (i=0; i < NREADS; i++) { | |
| 424 CLEAROOB(); | |
| 425 wait_for_tick(); | |
| 426 get_timestamp(&ft[i].start); | |
| 427 cyg_nandp_read_page(part, pg, 0, oob, oobz); | |
| 428 get_timestamp(&ft[i].end); | |
| 429 CHECKOOB(); | |
| 430 ++pg; | |
| 431 if (pg > pgend) pg = pgstart; | |
| 432 } | |
| 433 show_times(ft, NREADS, "NAND page reads (OOB only)"); | |
| 434 | |
| 435 for (i=0; i < NREADS; i++) { | |
| 436 CLEARDATA(); | |
| 437 CLEAROOB(); | |
| 438 wait_for_tick(); | |
| 439 get_timestamp(&ft[i].start); | |
| 440 cyg_nandp_read_page(part, pg, testbuf, oob, oobz); | |
| 441 get_timestamp(&ft[i].end); | |
| 442 CHECKDATA(); | |
| 443 CHECKOOB(); | |
| 444 ++pg; | |
| 445 if (pg > pgend) pg = pgstart; | |
| 446 } | |
| 447 show_times(ft, NREADS, "NAND page reads (page + OOB)"); | |
| 448 | |
| 449 #undef ft | |
| 450 #define ft ft_bulkread | |
| 451 for (i=0; i < NBULKREADS; i++) { | |
| 452 CLEARDATA(); | |
| 453 wait_for_tick(); | |
| 454 get_timestamp(&ft[i].start); | |
| 455 for (pg = pgstart; pg <= pgend; pg++) { | |
| 456 cyg_nandp_read_page(part, pg, testbuf, 0, 0); | |
| 457 } | |
| 458 get_timestamp(&ft[i].end); | |
| 459 CHECKDATA(); | |
| 460 } | |
| 461 // report the results later. | |
| 462 #undef ft | |
| 463 cyg_nandp_erase_block(part, b); | |
| 464 } | |
| 465 | |
| 466 | |
| 467 void test_writes(cyg_nand_partition *part, cyg_nand_block_addr b) | |
| 468 { | |
| 469 cyg_nand_page_addr pgstart = CYG_NAND_BLOCK2PAGEADDR(part->dev, b), | |
| 470 pgend = CYG_NAND_BLOCK2PAGEADDR(part->dev, b+1)-1, | |
| 471 pg = pgstart; | |
| 472 int i; | |
| 473 const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); | |
| 474 unsigned char oob[oobz]; | |
| 475 #define ft ft_write | |
| 476 | |
| 477 cyg_nandp_erase_block(part, b); | |
| 478 for (i=0; i < NWRITES; i++) { | |
| 479 wait_for_tick(); | |
| 480 get_timestamp(&ft[i].start); | |
| 481 cyg_nandp_write_page(part, pg, databuf, databuf, oobz); | |
| 482 get_timestamp(&ft[i].end); | |
| 483 | |
| 484 // Read it back to confirm | |
| 485 CLEARDATA(); | |
| 486 CLEAROOB(); | |
| 487 cyg_nandp_read_page(part, pg, testbuf, oob, oobz); | |
| 488 CHECKDATA(); | |
| 489 CHECKOOB(); | |
| 490 | |
| 491 ++pg; | |
| 492 if (pg > pgend) { | |
| 493 cyg_nandp_erase_block(part, b); | |
| 494 pg = pgstart; | |
| 495 } | |
| 496 } | |
| 497 cyg_nandp_erase_block(part, b); | |
| 498 show_times(ft, NWRITES, "NAND full-page writes"); | |
| 499 | |
| 500 #undef ft | |
| 501 #define ft ft_bulkwrite | |
| 502 // N.B. Bulk writing times will likely improve later if we implement cache-programming mode as found on many a large-page device. | |
| 503 for (i=0; i < NBULKWRITES; i++) { | |
| 504 wait_for_tick(); | |
| 505 get_timestamp(&ft[i].start); | |
| 506 for (pg = pgstart; pg <= pgend; pg++) { | |
| 507 cyg_nandp_write_page(part, pg, testbuf, 0, 0); | |
| 508 } | |
| 509 get_timestamp(&ft[i].end); | |
| 510 cyg_nandp_erase_block(part, b); | |
| 511 } | |
| 512 // report later. | |
| 513 #undef ft | |
| 514 } | |
| 515 | |
| 516 | |
| 517 void test_erases(cyg_nand_partition *part, cyg_nand_block_addr b) | |
| 518 { | |
| 519 int i; | |
| 520 #define ft ft_erase | |
| 521 | |
| 522 for (i=0; i < NERASES; i++) { | |
| 523 wait_for_tick(); | |
| 524 get_timestamp(&ft[i].start); | |
| 525 cyg_nandp_erase_block(part, b); | |
| 526 get_timestamp(&ft[i].end); | |
| 527 | |
| 528 if (i==0) { | |
| 529 cyg_nand_page_addr pg = CYG_NAND_BLOCK2PAGEADDR(part->dev, b); | |
| 530 const int oobz = CYG_NAND_APPSPARE_PER_PAGE(part->dev); | |
| 531 unsigned char oob[oobz]; | |
| 532 int j; | |
| 533 // TODO: It only makes sense to check the one, unless we want | |
| 534 // to try writing out more dummy data each time. | |
| 535 CLEARDATA(); | |
| 536 CLEAROOB(); | |
| 537 cyg_nandp_read_page(part, pg, testbuf, oob, oobz); | |
| 538 for (j=0; j < sizeof testbuf; j++) { | |
| 539 if (testbuf[j] != 0xff) { | |
| 540 CYG_TEST_FAIL("readback check failed"); | |
| 541 ++fails; | |
| 542 break; | |
| 543 } | |
| 544 } | |
| 545 for (j=0; j < oobz; j++) { | |
| 546 if (oob[j] != 0xff) { | |
| 547 CYG_TEST_FAIL("readback OOB check failed"); | |
| 548 ++fails; | |
| 549 break; | |
| 550 } | |
| 551 } | |
| 552 } | |
| 553 } | |
| 554 show_times(ft, NERASES, "NAND block erases"); | |
| 555 #undef ft | |
| 556 } | |
| 557 | |
| 558 | |
| 559 | |
| 560 void rwbenchmark_main(void) | |
| 561 { | |
| 562 cyg_nand_device *dev; | |
| 563 cyg_nand_partition *part; | |
| 564 cyg_nand_block_addr block; | |
| 565 | |
| 566 cyg_nand_lookup(DEVICE, &dev); | |
| 567 if (!dev) | |
| 568 CYG_TEST_FAIL_EXIT("can't get device "DEVICE); | |
|
3394
7905ed422fdf
io/nand: Rename CYGINT_IO_NAND_TEST_PARTITION to CYGNUM_IO_NAND_TEST_PARTITION.
Ross Younger <wry@ecoscentric.com>
parents:
3387
diff
changeset
|
569 part = cyg_nand_get_partition(dev, CYGNUM_IO_NAND_TEST_PARTITION); |
| 3017 | 570 if (!part) |
| 571 CYG_TEST_FAIL_EXIT("can't get partition"); | |
| 572 | |
| 573 block = find_spare_block(part); | |
| 574 diag_printf("Using block %d\n",block); | |
| 575 | |
| 576 show_test_parameters(dev); | |
| 577 show_times_hdr(); | |
| 578 | |
| 579 // TODO: For speed, refactor test_reads and test_writes into each other. | |
| 580 test_reads(part, block); | |
| 581 | |
| 582 // Freshen our test data for the second phase | |
| 583 ar4prng_many(&rnd, databuf, sizeof databuf); | |
| 584 test_writes(part,block); | |
| 585 | |
| 586 test_erases(part,block); | |
| 587 | |
| 588 show_times(ft_bulkread, NBULKREADS, "Bulk reads (block data)"); | |
| 589 show_times(ft_bulkwrite, NBULKWRITES, "Bulk writes (block data)"); | |
| 590 } | |
| 591 | |
| 592 int main(void) | |
| 593 { | |
| 594 CYG_TEST_INIT(); | |
| 595 init_timing(); | |
| 596 | |
| 597 ar4prng_init(&rnd,_stext, _etext-_stext); | |
| 598 ar4prng_many(&rnd, databuf, sizeof databuf); | |
| 599 | |
| 600 | |
| 601 #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) || defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) | |
| 602 CYG_TEST_INFO("WARNING: Clock or DSR latency instrumentation can mess with the results, recommend you turn it off."); | |
| 603 #endif | |
| 604 | |
| 605 | |
| 606 rwbenchmark_main(); | |
| 607 | |
| 608 if (fails) { | |
| 609 diag_printf("There were %d failures.\n",fails); | |
| 610 CYG_TEST_FAIL_FINISH("something went wrong, THESE RESULTS ARE INVALID"); | |
| 611 } | |
| 612 | |
| 613 CYG_TEST_PASS_FINISH("Benchmarking complete"); | |
| 614 } | |
| 615 | |
| 616 #endif | |
| 617 |
