Skip to content

bd: Add ProfilingBlockDevice for measuring higher-level applications #4844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions features/TESTS/filesystem/util_block_device/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "HeapBlockDevice.h"
#include "SlicingBlockDevice.h"
#include "ChainingBlockDevice.h"
#include "ProfilingBlockDevice.h"
#include <stdlib.h>

using namespace utest::v1;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
105 changes: 105 additions & 0 deletions features/filesystem/bd/ProfilingBlockDevice.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
159 changes: 159 additions & 0 deletions features/filesystem/bd/ProfilingBlockDevice.h
Original file line number Diff line number Diff line change
@@ -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