Skip to content

Instantly share code, notes, and snippets.

@pan-
Last active August 3, 2017 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pan-/b136a3d56200c0f1647d43d1315ed427 to your computer and use it in GitHub Desktop.
Save pan-/b136a3d56200c0f1647d43d1315ed427 to your computer and use it in GitHub Desktop.
static instrumentation framework
class BlockDeviceInstrumentCounter : public DefaultBlockDeviceInstrument {
public:
BlockDeviceInstrumentCounter() : counter(0) { }
void reset() {
counter = 0;
}
size_t get_counter() const {
return counter;
}
protected:
size_t counter;
};
template<typename Base, typename Discriminator>
struct Leaf : public Base { };
template<
typename Instrument1,
typename Instrument2
>
struct CompositeBlockDeviceInstrument :
public Leaf<
Instrument1, CompositeBlockDeviceInstrument<Instrument1, Instrument2>
>,
public Leaf<
Instrument2, CompositeBlockDeviceInstrument<Instrument1, Instrument2>
> {
typedef Leaf<Instrument1, CompositeBlockDeviceInstrument<Instrument1, Instrument2> > I1;
typedef Leaf<Instrument2, CompositeBlockDeviceInstrument<Instrument1, Instrument2> > I2;
CompositeBlockDeviceInstrument() : I1(), I2() { }
void before_read(void *buffer, bd_addr_t addr, bd_size_t size) {
I1::before_read(buffer, addr, size);
I2::before_read(buffer, addr, size);
}
void after_read(int result, void *buffer, bd_addr_t addr, bd_size_t size) {
I1::after_read(result, buffer, addr, size);
I2::after_read(result, buffer, addr, size);
}
void before_program(const void *buffer, bd_addr_t addr, bd_size_t size) {
I1::before_program(buffer, addr, size);
I2::before_program(buffer, addr, size);
}
void after_program(int result, const void *buffer, bd_addr_t addr, bd_size_t size) {
I1::after_program(result, buffer, addr, size);
I2::after_program(result, buffer, addr, size);
}
void before_erase(bd_addr_t addr, bd_size_t size) {
I1::before_erase(addr, size);
I2::before_erase(addr, size);
}
void after_erase(int result, bd_addr_t addr, bd_size_t size) {
I1::after_erase(result, addr, size);
I2::after_erase(result, addr, size);
}
void reset() {
I1::reset();
I2::reset();
}
template<typename T>
T& as() {
return static_cast<T&>(*this);
}
};
struct DefaultBlockDeviceInstrument {
void before_read(void *buffer, bd_addr_t addr, bd_size_t size) { }
void after_read(int result, void *buffer, bd_addr_t addr, bd_size_t size) { }
void before_program(const void *buffer, bd_addr_t addr, bd_size_t size) { }
void after_program(int result, const void *buffer, bd_addr_t addr, bd_size_t size) { }
void before_erase(bd_addr_t addr, bd_size_t size) { }
void after_erase(int result, bd_addr_t addr, bd_size_t size) { }
void reset() { }
};
void foo(BlockDevice* block_device) {
{
InstrumentedBlockDevice<BlockDeviceReadFaillureCounter> foo(block_device);
// do work
size_t faillures = foo.get_instrument().get_counter();
}
{
InstrumentedBlockDevice<
CompositeBlockDeviceInstrument<
BlockDeviceReadFaillureCounter, BlockDeviceReadCounter
>
> bar(block_device);
size_t read_faillure = bar.get_instrument().as<BlockDeviceReadFaillureCounter>().get_counter();
size_t read_counter = bar.get_instrument().as<BlockDeviceReadCounter>().get_counter();
}
{
InstrumentedBlockDevice<
CompositeBlockDeviceInstrument<
BlockDeviceReadFaillureCounter,
CompositeBlockDeviceInstrument<
BlockDeviceReadCounter, BlockDeviceReadTimingCounter
>
>
> baz(block_device);
size_t read_faillure = bar.get_instrument().as<BlockDeviceReadFaillureCounter>().get_counter();
size_t read_counter = bar.get_instrument().as<BlockDeviceReadCounter>().get_counter();
size_t read_timing_counter = bar.get_instrument().as<BlockDeviceReadTimingCounter>().get_counter();
}
}
class BlockDeviceReadCounter : public BlockDeviceInstrumentCounter {
public:
void after_read(int result, void *buffer, bd_addr_t addr, bd_size_t size) {
if (result == 0) {
counter += size;
}
}
};
class BlockDeviceReadFaillureCounter : public BlockDeviceInstrumentCounter {
public:
void after_read(int result, void *buffer, bd_addr_t addr, bd_size_t size) {
if (result != 0) {
++counter;
}
}
};
class BlockDeviceReadTimingCounter : public BlockDeviceInstrumentCounter {
public:
void before_read(void *buffer, bd_addr_t addr, bd_size_t size) {
timer.reset();
}
void after_read(int result, void *buffer, bd_addr_t addr, bd_size_t size) {
if (result != 0) {
counter += timer.read_ms();
}
}
Timer timer;
};
template<typename Instrument>
class InstrumentedBlockDevice : public BlockDevice {
public:
InstrumentedBlockDevice(BlockDevice* device) :
_block_device(device), _instrument() { }
virtual int read(void *buffer, bd_addr_t addr, bd_size_t size) {
_instrument.before_read(buffer, addr, size);
int result = _block_device->read(buffer, addr, size);
_instrument.after_read(result, buffer, addr, size);
return result;
}
virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size) {
_instrument.before_program(buffer, addr, size);
int result = _block_device->program(buffer, addr, size);
_instrument.after_program(result, buffer, addr, size);
return result;
}
virtual int erase(bd_addr_t addr, bd_size_t size) {
_instrument.before_erase(addr, size);
int result = _block_device->erase(addr, size);
_instrument.after_erase(result, addr, size);
return result;
}
Instrument get_instrument() {
return _instrument;
}
private:
BlockDevice* _block_device;
Instrument _instrument;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment