mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			bd: Added ProfilingBlockDevice for measuring higher-level applications
							parent
							
								
									2305a8c7e4
								
							
						
					
					
						commit
						d61073783c
					
				| 
						 | 
				
			
			@ -21,6 +21,7 @@
 | 
			
		|||
#include "HeapBlockDevice.h"
 | 
			
		||||
#include "SlicingBlockDevice.h"
 | 
			
		||||
#include "ChainingBlockDevice.h"
 | 
			
		||||
#include "ProfilingBlockDevice.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
using namespace utest::v1;
 | 
			
		||||
| 
						 | 
				
			
			@ -176,6 +177,67 @@ void test_chaining() {
 | 
			
		|||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Simple test which read/writes blocks on a chain of block devices
 | 
			
		||||
void test_profiling() {
 | 
			
		||||
    HeapBlockDevice bd(BLOCK_COUNT*BLOCK_SIZE, BLOCK_SIZE);
 | 
			
		||||
    uint8_t *write_block = new uint8_t[BLOCK_SIZE];
 | 
			
		||||
    uint8_t *read_block = new uint8_t[BLOCK_SIZE];
 | 
			
		||||
 | 
			
		||||
    // Test under profiling
 | 
			
		||||
    ProfilingBlockDevice profiler(&bd);
 | 
			
		||||
 | 
			
		||||
    int err = profiler.init();
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
 | 
			
		||||
    TEST_ASSERT_EQUAL(BLOCK_SIZE, profiler.get_erase_size());
 | 
			
		||||
    TEST_ASSERT_EQUAL(BLOCK_COUNT*BLOCK_SIZE, profiler.size());
 | 
			
		||||
 | 
			
		||||
    // Fill with random sequence
 | 
			
		||||
    srand(1);
 | 
			
		||||
    for (int i = 0; i < BLOCK_SIZE; i++) {
 | 
			
		||||
        write_block[i] = 0xff & rand();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Write, sync, and read the block
 | 
			
		||||
    err = profiler.erase(0, BLOCK_SIZE);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
 | 
			
		||||
    err = profiler.program(write_block, 0, BLOCK_SIZE);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
 | 
			
		||||
    err = profiler.read(read_block, 0, BLOCK_SIZE);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
 | 
			
		||||
    // Check that the data was unmodified
 | 
			
		||||
    srand(1);
 | 
			
		||||
    for (int i = 0; i < BLOCK_SIZE; i++) {
 | 
			
		||||
        TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check with original block device
 | 
			
		||||
    err = bd.read(read_block, 0, BLOCK_SIZE);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
 | 
			
		||||
    // Check that the data was unmodified
 | 
			
		||||
    srand(1);
 | 
			
		||||
    for (int i = 0; i < BLOCK_SIZE; i++) {
 | 
			
		||||
        TEST_ASSERT_EQUAL(0xff & rand(), read_block[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    delete[] write_block;
 | 
			
		||||
    delete[] read_block;
 | 
			
		||||
    err = profiler.deinit();
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, err);
 | 
			
		||||
 | 
			
		||||
    // Check that profiled operations match expectations
 | 
			
		||||
    bd_size_t read_count = profiler.get_read_count();
 | 
			
		||||
    TEST_ASSERT_EQUAL(BLOCK_SIZE, read_count);
 | 
			
		||||
    bd_size_t program_count = profiler.get_program_count();
 | 
			
		||||
    TEST_ASSERT_EQUAL(BLOCK_SIZE, program_count);
 | 
			
		||||
    bd_size_t erase_count = profiler.get_erase_count();
 | 
			
		||||
    TEST_ASSERT_EQUAL(BLOCK_SIZE, erase_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Test setup
 | 
			
		||||
utest::v1::status_t test_setup(const size_t number_of_cases) {
 | 
			
		||||
| 
						 | 
				
			
			@ -186,6 +248,7 @@ utest::v1::status_t test_setup(const size_t number_of_cases) {
 | 
			
		|||
Case cases[] = {
 | 
			
		||||
    Case("Testing slicing of a block device", test_slicing),
 | 
			
		||||
    Case("Testing chaining of block devices", test_chaining),
 | 
			
		||||
    Case("Testing profiling of block devices", test_profiling),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Specification specification(test_setup, cases);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,105 @@
 | 
			
		|||
/* mbed Microcontroller Library
 | 
			
		||||
 * Copyright (c) 2017 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ProfilingBlockDevice.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ProfilingBlockDevice::ProfilingBlockDevice(BlockDevice *bd)
 | 
			
		||||
    : _bd(bd)
 | 
			
		||||
    , _read_count(0)
 | 
			
		||||
    , _program_count(0)
 | 
			
		||||
    , _erase_count(0)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ProfilingBlockDevice::init()
 | 
			
		||||
{
 | 
			
		||||
    return _bd->init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ProfilingBlockDevice::deinit()
 | 
			
		||||
{
 | 
			
		||||
    return _bd->deinit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ProfilingBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
 | 
			
		||||
{
 | 
			
		||||
    int err = _bd->read(b, addr, size);
 | 
			
		||||
    if (!err) {
 | 
			
		||||
        _read_count += size;
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ProfilingBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
 | 
			
		||||
{
 | 
			
		||||
    int err = _bd->program(b, addr, size);
 | 
			
		||||
    if (!err) {
 | 
			
		||||
        _program_count += size;
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ProfilingBlockDevice::erase(bd_addr_t addr, bd_size_t size)
 | 
			
		||||
{
 | 
			
		||||
    int err = _bd->erase(addr, size);
 | 
			
		||||
    if (!err) {
 | 
			
		||||
        _erase_count += size;
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::get_read_size() const
 | 
			
		||||
{
 | 
			
		||||
    return _bd->get_read_size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::get_program_size() const
 | 
			
		||||
{
 | 
			
		||||
    return _bd->get_program_size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::get_erase_size() const
 | 
			
		||||
{
 | 
			
		||||
    return _bd->get_erase_size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::size() const
 | 
			
		||||
{
 | 
			
		||||
    return _bd->size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProfilingBlockDevice::reset()
 | 
			
		||||
{
 | 
			
		||||
    _read_count = 0;
 | 
			
		||||
    _program_count = 0;
 | 
			
		||||
    _erase_count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::get_read_count() const
 | 
			
		||||
{
 | 
			
		||||
    return _read_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::get_program_count() const
 | 
			
		||||
{
 | 
			
		||||
    return _program_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bd_size_t ProfilingBlockDevice::get_erase_count() const
 | 
			
		||||
{
 | 
			
		||||
    return _erase_count;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,159 @@
 | 
			
		|||
/* mbed Microcontroller Library
 | 
			
		||||
 * Copyright (c) 2017 ARM Limited
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef MBED_PROFILING_BLOCK_DEVICE_H
 | 
			
		||||
#define MBED_PROFILING_BLOCK_DEVICE_H
 | 
			
		||||
 | 
			
		||||
#include "BlockDevice.h"
 | 
			
		||||
#include "mbed.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** Block device for measuring storage operations of another block device
 | 
			
		||||
 *
 | 
			
		||||
 *  @code
 | 
			
		||||
 *  #include "mbed.h"
 | 
			
		||||
 *  #include "HeapBlockDevice.h"
 | 
			
		||||
 *  #include "ProfilingBlockDevice.h"
 | 
			
		||||
 *
 | 
			
		||||
 *  // Create a heap block device and profiling block device
 | 
			
		||||
 *  HeapBlockDevice mem(64*512, 512);
 | 
			
		||||
 *  ProfilingBlockDevice profiler(&mem);
 | 
			
		||||
 *
 | 
			
		||||
 *  // do block device work....
 | 
			
		||||
 *
 | 
			
		||||
 *  printf("read count: %lld\n", profiler.get_read_count());
 | 
			
		||||
 *  printf("program count: %lld\n", profiler.get_program_count());
 | 
			
		||||
 *  printf("erase count: %lld\n", profiler.get_erase_count());
 | 
			
		||||
 */
 | 
			
		||||
class ProfilingBlockDevice : public BlockDevice
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Lifetime of the memory block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @param bd       Block device to back the ProfilingBlockDevice
 | 
			
		||||
     */
 | 
			
		||||
    ProfilingBlockDevice(BlockDevice *bd);
 | 
			
		||||
 | 
			
		||||
    /** Lifetime of a block device
 | 
			
		||||
     */
 | 
			
		||||
    virtual ~ProfilingBlockDevice() {};
 | 
			
		||||
 | 
			
		||||
    /** Initialize a block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @return         0 on success or a negative error code on failure
 | 
			
		||||
     *  @note The init and deinit functions do not effect profile counts
 | 
			
		||||
     */
 | 
			
		||||
    virtual int init();
 | 
			
		||||
 | 
			
		||||
    /** Deinitialize a block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @return         0 on success or a negative error code on failure
 | 
			
		||||
     *  @note The init and deinit functions do not effect profile counts
 | 
			
		||||
     */
 | 
			
		||||
    virtual int deinit();
 | 
			
		||||
 | 
			
		||||
    /** Read blocks from a block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @param buffer   Buffer to read blocks into
 | 
			
		||||
     *  @param addr     Address of block to begin reading from
 | 
			
		||||
     *  @param size     Size to read in bytes, must be a multiple of read block size
 | 
			
		||||
     *  @return         0 on success, negative error code on failure
 | 
			
		||||
     */
 | 
			
		||||
    virtual int read(void *buffer, bd_addr_t addr, bd_size_t size);
 | 
			
		||||
 | 
			
		||||
    /** Program blocks to a block device
 | 
			
		||||
     *
 | 
			
		||||
     *  The blocks must have been erased prior to being programmed
 | 
			
		||||
     *
 | 
			
		||||
     *  @param buffer   Buffer of data to write to blocks
 | 
			
		||||
     *  @param addr     Address of block to begin writing to
 | 
			
		||||
     *  @param size     Size to write in bytes, must be a multiple of program block size
 | 
			
		||||
     *  @return         0 on success, negative error code on failure
 | 
			
		||||
     */
 | 
			
		||||
    virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);
 | 
			
		||||
 | 
			
		||||
    /** Erase blocks on a block device
 | 
			
		||||
     *
 | 
			
		||||
     *  The state of an erased block is undefined until it has been programmed
 | 
			
		||||
     *
 | 
			
		||||
     *  @param addr     Address of block to begin erasing
 | 
			
		||||
     *  @param size     Size to erase in bytes, must be a multiple of erase block size
 | 
			
		||||
     *  @return         0 on success, negative error code on failure
 | 
			
		||||
     */
 | 
			
		||||
    virtual int erase(bd_addr_t addr, bd_size_t size);
 | 
			
		||||
 | 
			
		||||
    /** Get the size of a readable block
 | 
			
		||||
     *
 | 
			
		||||
     *  @return         Size of a readable block in bytes
 | 
			
		||||
     */
 | 
			
		||||
    virtual bd_size_t get_read_size() const;
 | 
			
		||||
 | 
			
		||||
    /** Get the size of a programable block
 | 
			
		||||
     *
 | 
			
		||||
     *  @return         Size of a programable block in bytes
 | 
			
		||||
     *  @note Must be a multiple of the read size
 | 
			
		||||
     */
 | 
			
		||||
    virtual bd_size_t get_program_size() const;
 | 
			
		||||
 | 
			
		||||
    /** Get the size of a eraseable block
 | 
			
		||||
     *
 | 
			
		||||
     *  @return         Size of a eraseable block in bytes
 | 
			
		||||
     *  @note Must be a multiple of the program size
 | 
			
		||||
     */
 | 
			
		||||
    virtual bd_size_t get_erase_size() const;
 | 
			
		||||
 | 
			
		||||
    /** Get the total size of the underlying device
 | 
			
		||||
     *
 | 
			
		||||
     *  @return         Size of the underlying device in bytes
 | 
			
		||||
     */
 | 
			
		||||
    virtual bd_size_t size() const;
 | 
			
		||||
 | 
			
		||||
    /** Reset the current profile counts to zero
 | 
			
		||||
     */
 | 
			
		||||
    void reset();
 | 
			
		||||
 | 
			
		||||
    /** Get number of bytes that have been read from the block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @return The number of bytes that have been read from the block device
 | 
			
		||||
     */
 | 
			
		||||
    bd_size_t get_read_count() const;
 | 
			
		||||
 | 
			
		||||
    /** Get number of bytes that have been programed to the block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @return The number of bytes that have been programed to the block device
 | 
			
		||||
     */
 | 
			
		||||
    bd_size_t get_program_count() const;
 | 
			
		||||
 | 
			
		||||
    /** Get number of bytes that have been erased from the block device
 | 
			
		||||
     *
 | 
			
		||||
     *  @return The number of bytes that have been erased from the block device
 | 
			
		||||
     */
 | 
			
		||||
    bd_size_t get_erase_count() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    BlockDevice *_bd;
 | 
			
		||||
    bd_size_t _read_count;
 | 
			
		||||
    bd_size_t _program_count;
 | 
			
		||||
    bd_size_t _erase_count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
		Reference in New Issue