Skip to content

Commit

Permalink
Add channel controller base class (#165)
Browse files Browse the repository at this point in the history
* Add ChannelController class

* Add some ChannelController documentation
  • Loading branch information
daboehme authored Apr 16, 2019
1 parent df66c0f commit d33831c
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 0 deletions.
83 changes: 83 additions & 0 deletions include/caliper/ChannelController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/// \file ChannelController.h
/// ChannelController class

#pragma once

#include "cali_definitions.h"

#include <map>
#include <memory>
#include <string>

namespace cali
{

class Caliper;
class Channel;

typedef std::map<std::string, std::string> config_map_t;

/// \class ChannelController
/// \brief Base class for %Caliper channel controllers
///
/// A channel controller wraps a %Caliper configuration and channel.
/// The underlying channel is initially inactive, and will be created
/// in the first call of the start() method. Derived classes can
/// modify the configuration before the channel is created.
///
/// ChannelController objects can be copied and moved. The underlying
/// %Caliper channel will be deleted when the last ChannelController
/// object referencing is destroyed.

class ChannelController
{
struct ChannelControllerImpl;
std::shared_ptr<ChannelControllerImpl> mP;

protected:

/// \brief Return the underlying %Caliper channel object.
Channel* channel();

/// \brief Provide access to the underlying config map.
///
/// Note that configuration modifications are only effective before
/// the underlying %Caliper channel has been created.
config_map_t& config();

/// \brief Create the channel with the controller's
/// name, flags, and config map
Channel* create();

/// \brief Callback function, invoked after the underlying channel
/// has been created.
///
/// This can be used to setup additional functionality, e.g.
/// registering %Caliper callbacks.
virtual void on_create(Caliper* c, Channel* chn) { }

public:

/// \brief Create and activate the %Caliper channel,
/// or reactivate a stopped %Caliper channel.
void start();

/// \brief Deactivate the %Caliper channel.
void stop();

/// \brief Returns true if channel exists and is active, false otherwise.
bool is_active() const;

/// \brief Flush the underlying %Caliper channel.
///
/// Allows derived classes to implement custom %Caliper data processing.
/// The base class implementation invokes Caliper::flush_and_write().
virtual void flush();

/// \brief Create channel controller with given name, flags, and config.
ChannelController(const char* name, int flags, const config_map_t& cfg);

virtual ~ChannelController();
};

} // namespace cali;
1 change: 1 addition & 0 deletions src/caliper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set(CALIPER_SOURCES
AnnotationBinding.cpp
Blackboard.cpp
Caliper.cpp
ChannelController.cpp
SnapshotRecord.cpp
MemoryPool.cpp
MetadataTree.cpp
Expand Down
114 changes: 114 additions & 0 deletions src/caliper/ChannelController.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include "caliper/ChannelController.h"

#include "caliper/common/Log.h"
#include "caliper/common/RuntimeConfig.h"

#include "caliper/Caliper.h"

using namespace cali;

struct ChannelController::ChannelControllerImpl
{
std::string name;
int flags;
config_map_t config;

Channel* channel = nullptr;

ChannelControllerImpl(const char* cname, int cflags, const config_map_t& cfg)
: name(cname),
flags(cflags),
config(cfg)
{ }

~ChannelControllerImpl() {
if (channel) {
Caliper c;
c.delete_channel(channel);
}
}
};

Channel*
ChannelController::channel()
{
return mP->channel;
}

config_map_t&
ChannelController::config()
{
return mP->config;
}

Channel*
ChannelController::create()
{
if (mP->channel)
return mP->channel;

RuntimeConfig cfg;

cfg.allow_read_env(mP->flags & CALI_CHANNEL_ALLOW_READ_ENV);
cfg.import(mP->config);

Caliper c;

mP->channel = c.create_channel(mP->name.c_str(), cfg);

if (!mP->channel) {
Log(0).stream() << "ChannelController::create(): Could not create channel "
<< mP->name << std::endl;
return nullptr;
}

if (mP->flags & CALI_CHANNEL_LEAVE_INACTIVE)
c.deactivate_channel(mP->channel);

on_create(&c, mP->channel);

return mP->channel;
}

void
ChannelController::start()
{
Caliper c;
Channel* chn = mP->channel;

if (!chn)
chn = create();
if (chn)
c.activate_channel(chn);
}

void
ChannelController::stop()
{
if (mP->channel)
Caliper().deactivate_channel(mP->channel);
}

bool
ChannelController::is_active() const
{
return mP->channel && mP->channel->is_active();
}

void
ChannelController::flush()
{
Channel* chn = channel();

if (chn)
Caliper().flush_and_write(chn, nullptr);
}

ChannelController::ChannelController(const char* name, int flags, const config_map_t& cfg)
: mP { new ChannelControllerImpl(name, flags, cfg) }
{
}

ChannelController::~ChannelController()
{
}
1 change: 1 addition & 0 deletions src/caliper/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ set(CALIPER_TEST_SOURCES
test_attribute.cpp
test_blackboard.cpp
test_channel_api.cpp
test_channel_controller.cpp
test_metadatatree.cpp
test_c_snapshot.cpp)

Expand Down
47 changes: 47 additions & 0 deletions src/caliper/test/test_channel_controller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "caliper/cali.h"
#include "caliper/ChannelController.h"

#include "caliper/Caliper.h"

#include <gtest/gtest.h>

using namespace cali;

TEST(ChannelControllerTest, ChannelController)
{
struct TestCC : public ChannelController {
bool saw_create_callback = false;
Channel* the_channel = nullptr;

void on_create(Caliper*, Channel* chn) {
saw_create_callback = true;
the_channel = chn;
}

TestCC()
: ChannelController("testCC", 0, {
{ "CALI_CHANNEL_FLUSH_ON_EXIT", "false" },
{ "CALI_CHANNEL_CONFIG_CHECK", "false" }
})
{ }
};

TestCC testCC;

EXPECT_FALSE(testCC.is_active());
EXPECT_FALSE(testCC.saw_create_callback);

testCC.stop(); // shouldn't do anything

testCC.start();

EXPECT_TRUE(testCC.is_active());
EXPECT_TRUE(testCC.saw_create_callback);

ASSERT_NE(testCC.the_channel, nullptr);
EXPECT_EQ(testCC.the_channel->name(), std::string("testCC"));

testCC.stop();

EXPECT_FALSE(testCC.is_active());
}

0 comments on commit d33831c

Please sign in to comment.