Mercurial > nand-ecoscentric
changeset 2976:758f9d488949
NAND: Add timing instrumentation hooks (disabled by default)
| author | Ross Younger <wry@ecoscentric.com> |
|---|---|
| date | Tue, 10 Nov 2009 18:25:39 +0000 |
| parents | 7050b2f79b6e |
| children | 7a3f0b89a102 |
| files | packages/io/nand/current/ChangeLog packages/io/nand/current/cdl/nand.cdl packages/io/nand/current/misc/timetag_to_csv.pl packages/io/nand/current/src/nand.c |
| diffstat | 4 files changed, 167 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/io/nand/current/ChangeLog +++ b/packages/io/nand/current/ChangeLog @@ -1,16 +1,22 @@ +2009-11-12 Ross Younger <wry@eCosCentric.com> + + * nand.c: Add timing instrumentation hooks. + * nand.cdl: Add CYGSEM_IO_NAND_INSTRUMENT_TIMING to mediate them. + * misc/timetag_to_csv.pl: Helper perl script for use with them. + 2009-11-09 Ross Younger <wry@eCosCentric.com> * nand.h: Rationalise interface: * read_page: now only reads a whole page and/or its spare. * read_part_page: Created. Allows part-pages and optionally - not checking ECC. + not checking ECC. * write_page: now only writes a whole page and/or its spare. + nand_ecc.h: Drop earlier attempt to support sub-page ECC. * tests/readwrite.c: Test out cyg_nand_read_part_page(). * tests: Update for interface tweak. * nand_bbt.c: Rationalise BBT finding into one place and fix to - better cope with the situation where only one BBT block had - been written. Cure an internal race. + better cope with the situation where only one BBT block had + been written. Cure an internal race. * nand_ecc_mtd_fast.c: Speed up checking phase. 2009-11-06 Ross Younger <wry@eCosCentric.com>
--- a/packages/io/nand/current/cdl/nand.cdl +++ b/packages/io/nand/current/cdl/nand.cdl @@ -239,6 +239,15 @@ cdl_package CYGPKG_IO_NAND { played with lightly." } + cdl_option CYGSEM_IO_NAND_INSTRUMENT_TIMING { + display "Instrument NAND call timings" + default_value 0 + description "This option enables timing instrumentation within + the NAND library. It is intended only to assist driver + authors during development. + Normal users should not set this option." + } + cdl_option CYGBLD_IO_NAND_UTILS { display "The list of utilities to build." flavor data
new file mode 100644 --- /dev/null +++ b/packages/io/nand/current/misc/timetag_to_csv.pl @@ -0,0 +1,71 @@ +#!/usr/bin/perl -ln +# +# timetag_to_csv.pl +# Reformats some timetags as output from gdb ("p tagslist") as CSV +# for easy import into your analysis tool of choice. +# +# ####ECOSGPLCOPYRIGHTBEGIN#### +# ------------------------------------------- +# This file is part of eCos, the Embedded Configurable Operating System. +# Copyright (C) 2009 eCosCentric Limited. +# +# eCos 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 or (at your option) any later +# version. +# +# eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# As a special exception, if other files instantiate templates or use +# macros or inline functions from this file, or you compile this file +# and link it with other works to produce a work based on this file, +# this file does not by itself cause the resulting work to be covered by +# the GNU General Public License. However the source code for this file +# must still be made available in accordance with section (3) of the GNU +# General Public License v2. +# +# This exception does not invalidate any other reasons why a work based +# on this file might be covered by the GNU General Public License. +# ------------------------------------------- +# ####ECOSGPLCOPYRIGHTEND#### +# +# ####DESCRIPTIONBEGIN#### +# +# Author(s): wry +# Date: 2009-11-10 +# +# ###DESCRIPTIONEND#### +# + +# input (stdin or filename): paste from gdb ("p tagslist") +# output (stdout): csv + +BEGIN { my $state=0; my @data = (); } + +$state = 1 if s/.*{//; + +my $nextstate = $state; +$nextstate = 0 if s/}.*//; + +s/^\s+//; +s/\s+$//; +if ($state == 1) { + push @data, split /,\s*/; +} +$state = $nextstate; + +END { + while (@data) { + $a = shift @data; + $b = shift @data; + $c = shift @data; + print "$a, $b, $c"; + } +}
--- a/packages/io/nand/current/src/nand.c +++ b/packages/io/nand/current/src/nand.c @@ -58,6 +58,58 @@ #include <string.h> /* ============================================================ */ +// Timing instrumentation hooks; or "where is all the time going?" +// timetag_to_csv.pl will turn gdb output ("p tagslist") into CSV, +// for ease of analysis. + +#ifdef CYGSEM_IO_NAND_INSTRUMENT_TIMING +# ifndef HAL_CLOCK_READ +# error HAL_CLOCK_READ required +# endif +# define TAGSIZE 1024 +cyg_uint32 tagslist[TAGSIZE]; +cyg_uint32 tags_next; +static cyg_int64 rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static cyg_int64 rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; + +# define TAG(_x) do { \ + tagslist[tags_next++] = _x; \ + if (tags_next >= TAGSIZE) tags_next = 0; \ +} while(0) + +# define TIMETAG() do { \ + cyg_uint64 tick; \ + cyg_uint32 haltick; \ + tick=cyg_current_time();\ + HAL_CLOCK_READ(&haltick);\ + TAG(__LINE__); \ + TAG(tick&0xFFFFFFFF); \ + TAG(haltick); \ +} while(0) + +# define TIMETAG_INIT() do { \ + int _i; \ + for (_i=0; _i<TAGSIZE; _i++) \ + tagslist[_i]=0; \ + tags_next = 0; \ + cyg_uint32 _tt, _tu; \ + HAL_CLOCK_READ(&_tt); \ + _tu = _tt; \ + while (_tt == _tu) \ + HAL_CLOCK_READ(&_tu); \ + TIMETAG(); \ + (void) rtc_period; \ + (void) rtc_resolution; \ +} while(0) + +#else // ! CYGSEM_IO_NAND_INSTRUMENT_TIMING + +# define TIMETAG_INIT() CYG_EMPTY_STATEMENT +# define TIMETAG() CYG_EMPTY_STATEMENT + +#endif + +/* ============================================================ */ /* We have a global ("devinit") lock, protects the nanddevtab and all * writes to device->isInited. @@ -263,6 +315,7 @@ int cyg_nand_read_page(cyg_nand_partitio void * dest, void * spare, size_t spare_size) { int rv, locked=0; + TIMETAG_INIT(); PARTITION_CHECK(prt); cyg_nand_device *dev = prt->dev; DEV_INIT_CHECK(dev); @@ -285,6 +338,7 @@ int cyg_nand_read_page(cyg_nand_partitio err_exit: if (locked) UNLOCK_DEV(dev); + TIMETAG(); return rv; } @@ -368,7 +422,9 @@ int nandi_read_whole_page_raw(cyg_nand_d ++tries; remain = NAND_BYTES_PER_PAGE(dev); + TIMETAG(); EG(dev->fns->read_begin(dev, page)); + TIMETAG(); if (dest) { int step; @@ -376,22 +432,28 @@ int nandi_read_whole_page_raw(cyg_nand_d step = read_data_stride; CYG_ASSERTC(remain >= read_data_stride); + TIMETAG(); if (do_hw_ecc && dev->ecc->init) dev->ecc->init(dev); EG(dev->fns->read_stride(dev, data_dest, read_data_stride)); + TIMETAG(); if (do_hw_ecc) { dev->ecc->calc(dev, 0, ecc_dest); ecc_dest += ecc_stride; + TIMETAG(); } data_dest += read_data_stride; remain -= read_data_stride; } + TIMETAG(); EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page)); + TIMETAG(); nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf); if (check_ecc) { + TIMETAG(); if (!do_hw_ecc) { // Calculate software ECC in one go to try and take // advantage of the cache. @@ -433,9 +495,12 @@ int nandi_read_whole_page_raw(cyg_nand_d ecc_calc_p += ecc_stride; remain -= ecc_data_stride; } + TIMETAG(); } } else { // !dest: very simple case + TIMETAG(); EG(dev->fns->read_finish(dev, oob_buf, dev->spare_per_page)); + TIMETAG(); rv = 0; nand_oob_unpack(dev, spare, spare_size, ecc_read, oob_buf); } @@ -471,6 +536,7 @@ int cyg_nand_write_page(cyg_nand_partiti const void * src, const void * spare, size_t spare_size) { int rv, locked = 0; + TIMETAG_INIT(); PARTITION_CHECK(prt); cyg_nand_device *dev = prt->dev; DEV_INIT_CHECK(dev); @@ -490,6 +556,7 @@ int cyg_nand_write_page(cyg_nand_partiti err_exit: if (locked) UNLOCK_DEV(dev); + TIMETAG(); return rv; } @@ -517,6 +584,7 @@ int nandi_write_page_raw(cyg_nand_device if (spare) CYG_CHECK_DATA_PTRC(spare); CYG_ASSERTC(NAND_BYTES_PER_PAGE(dev) % ecc_data_stride == 0); + TIMETAG(); // If we're doing software ECC, do it all in one go now. if (src && !do_hw_ecc) { const CYG_BYTE *data_src = src; @@ -532,15 +600,18 @@ int nandi_write_page_raw(cyg_nand_device ecc_dest += ecc_stride; } } + TIMETAG(); EG(dev->fns->write_begin(dev, page)); + TIMETAG(); if (src) { remain = NAND_BYTES_PER_PAGE(dev); while (remain) { CYG_ASSERTC(remain >= write_data_stride); + TIMETAG(); if (do_hw_ecc && dev->ecc->init) dev->ecc->init(dev); - EG(dev->fns->write_stride(dev, src, write_data_stride)); + TIMETAG(); if (do_hw_ecc) { dev->ecc->calc(dev, 0, ecc_dest); ecc_dest += ecc_stride; @@ -549,10 +620,12 @@ int nandi_write_page_raw(cyg_nand_device remain -= write_data_stride; } } + TIMETAG(); nand_oob_pack(dev, spare, spare_size, ecc, oob_packed); NAND_CHATTER(8,dev,"Write page %u\n", page); EG(dev->fns->write_finish(dev, oob_packed, dev->spare_per_page)); + TIMETAG(); /* N.B. We don't read-back to verify; drivers may do so themselves if * they wish. Typically the spec sheet says that a read-back test @@ -575,7 +648,9 @@ int cyg_nand_erase_block(cyg_nand_partit int rv; DEV_INIT_CHECK(dev); + TIMETAG(); LOCK_DEV(dev); + TIMETAG(); EG(valid_block_addr(prt, blk)); #ifdef CYGSEM_IO_NAND_USE_BBT @@ -593,7 +668,9 @@ int cyg_nand_erase_block(cyg_nand_partit EG(rv); } err_exit: + TIMETAG(); UNLOCK_DEV(dev); + TIMETAG(); return rv; #endif }
