IVGCVSW-2531 Serialize a simple ArmNN Network
authorMike Kelly <mike.kelly@arm.com>
Mon, 11 Feb 2019 17:01:27 +0000 (17:01 +0000)
committerMike Kelly <mike.kelly@arm.com>
Mon, 11 Feb 2019 17:01:27 +0000 (17:01 +0000)
Change-Id: I68cf5072aca6e3a8b3b8c57e19b6d417cd5813fc
Signed-off-by: Mike Kelly <mike.kelly@arm.com>
18 files changed:
CMakeLists.txt
include/armnn/INetwork.hpp
include/armnn/LayerVisitorBase.hpp [moved from src/armnn/LayerVisitorBase.hpp with 100% similarity]
src/armnn/Layer.cpp
src/armnn/Layer.hpp
src/armnn/Network.cpp
src/armnn/Network.hpp
src/armnn/OverrideInputRangeVisitor.hpp
src/armnn/QuantizerVisitor.hpp
src/armnn/StaticRangeVisitor.hpp
src/armnn/test/QuantizerTest.cpp
src/armnnDeserializeParser/DeserializeParser.cpp
src/armnnSerializer/README.md [new file with mode: 0644]
src/armnnSerializer/Schema.fbs
src/armnnSerializer/SeralizerSupport.md [new file with mode: 0644]
src/armnnSerializer/Serializer.cpp [new file with mode: 0644]
src/armnnSerializer/Serializer.hpp [new file with mode: 0644]
src/armnnSerializer/test/SerializerTests.cpp [new file with mode: 0644]

index ea0f2c3..71b4dfe 100644 (file)
@@ -158,8 +158,10 @@ if(BUILD_ARMNN_SERIALIZER)
 
     set(armnn_serializer_sources)
     list(APPEND armnn_serializer_sources
-        src/armnnSerializer/Schema_generated.h
         include/armnnDeserializeParser/IDeserializeParser.hpp
+        src/armnnSerializer/Schema_generated.h
+        src/armnnSerializer/Serializer.hpp
+        src/armnnSerializer/Serializer.cpp
         src/armnnDeserializeParser/DeserializeParser.hpp
         src/armnnDeserializeParser/DeserializeParser.cpp
         )
@@ -188,6 +190,7 @@ list(APPEND armnn_sources
     include/armnn/IProfiler.hpp
     include/armnn/IRuntime.hpp
     include/armnn/LayerSupport.hpp
+    include/armnn/LayerVisitorBase.hpp
     include/armnn/LstmParams.hpp
     include/armnn/NetworkFwd.hpp
     include/armnn/Optional.hpp
@@ -303,7 +306,6 @@ list(APPEND armnn_sources
     src/armnn/LayersFwd.hpp
     src/armnn/LayerSupportCommon.hpp
     src/armnn/LayerSupport.cpp
-    src/armnn/LayerVisitorBase.hpp
     src/armnn/LoadedNetwork.cpp
     src/armnn/LoadedNetwork.hpp
     src/armnn/Network.cpp
@@ -546,6 +548,7 @@ if(BUILD_UNIT_TESTS)
         enable_language(ASM)
         list(APPEND unittest_sources
                 src/armnnSerializer/Schema_generated.h
+                src/armnnSerializer/test/SerializerTests.cpp
                 src/armnnDeserializeParser/test/DeserializeAdd.cpp
                 src/armnnDeserializeParser/test/ParserFlatbuffersSerializeFixture.hpp
                 src/armnnDeserializeParser/test/SchemaSerialize.s
@@ -581,10 +584,6 @@ if(BUILD_UNIT_TESTS)
     target_include_directories(UnitTests PRIVATE src/armnnUtils)
     target_include_directories(UnitTests PRIVATE src/backends)
 
-    if(BUILD_ARMNN_SERIALIZER)
-        target_include_directories(UnitTests SYSTEM PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/src/armnnSerializer")
-    endif()
-
     if(BUILD_TF_LITE_PARSER)
         target_include_directories(UnitTests SYSTEM PRIVATE "${TF_LITE_SCHEMA_INCLUDE_PATH}")
     endif()
@@ -613,6 +612,7 @@ if(BUILD_UNIT_TESTS)
     endif()
 
     if(BUILD_ARMNN_SERIALIZER)
+        target_include_directories(UnitTests SYSTEM PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src/armnnSerializer)
         target_link_libraries(UnitTests armnnSerializer)
     endif()
 
index c4c67b7..aaca13b 100644 (file)
@@ -17,7 +17,6 @@
 
 namespace armnn
 {
-
 /// @brief An input connection slot for a layer.
 /// The input slot can be connected to an output slot of the preceding layer in the graph.
 /// Only one connection to the input slot is allowed.
@@ -48,6 +47,10 @@ public:
     virtual int Connect(IInputSlot& destination) = 0;
     virtual void Disconnect(IInputSlot& slot) = 0;
 
+    virtual unsigned int CalculateIndexOnOwner() const = 0;
+
+    virtual LayerGuid GetOwningLayerGuid() const = 0;
+
 protected:
     /// Not user deletable.
     ~IOutputSlot() {}
@@ -361,6 +364,8 @@ public:
     /// @ return - Interface for configuring the layer.
     virtual IConnectableLayer* AddGatherLayer(const char* name = nullptr) = 0;
 
+    virtual void Accept(ILayerVisitor& visitor) const = 0;
+
 protected:
     ~INetwork() {}
 };
index c49dd61..0a6328b 100644 (file)
@@ -143,6 +143,11 @@ void OutputSlot::ValidateConnectionIndex(unsigned int index) const
     }
 }
 
+LayerGuid OutputSlot::GetOwningLayerGuid() const
+{
+    return GetOwningLayer().GetGuid();
+}
+
 namespace {
 LayerGuid GenerateLayerGuid()
 {
@@ -335,5 +340,4 @@ std::vector<TensorShape> Layer::InferOutputShapes(const std::vector<TensorShape>
     }
     return inputShapes;
 }
-
 } // namespace armnn
index c08c6b0..507b37b 100644 (file)
@@ -105,6 +105,8 @@ public:
 
     Layer& GetOwningLayer() const { return m_OwningLayer; }
 
+    LayerGuid GetOwningLayerGuid() const override;
+
     const OutputHandler& GetOutputHandler() const { return m_OutputHandler; }
     OutputHandler& GetOutputHandler() { return m_OutputHandler; }
 
@@ -141,7 +143,7 @@ public:
         return Disconnect(*boost::polymorphic_downcast<InputSlot*>(&slot));
     }
 
-    unsigned int CalculateIndexOnOwner() const;
+    unsigned int CalculateIndexOnOwner() const override;
 
     bool operator==(const OutputSlot& other) const;
 
index 5c70003..cad1690 100644 (file)
@@ -917,6 +917,14 @@ IConnectableLayer* Network::AddGatherLayer(const char* name)
     return m_Graph->AddLayer<GatherLayer>(name);
 }
 
+void Network::Accept(ILayerVisitor& visitor) const
+{
+    for (auto layer : GetGraph())
+    {
+        layer->Accept(visitor);
+    };
+}
+
 OptimizedNetwork::OptimizedNetwork(std::unique_ptr<Graph> graph)
     : m_Graph(std::move(graph))
 {
index 66fb240..3754c2e 100644 (file)
@@ -148,6 +148,8 @@ public:
 
     IConnectableLayer* AddRsqrtLayer(const char* name = nullptr) override;
 
+    void Accept(ILayerVisitor& visitor) const override;
+
 private:
     IConnectableLayer* AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor,
         const ConstTensor& weights,
index 0b1999f..72396b4 100644 (file)
@@ -6,7 +6,7 @@
 #pragma once
 
 #include "NetworkQuantizer.hpp"
-#include "LayerVisitorBase.hpp"
+#include "armnn/LayerVisitorBase.hpp"
 
 #include <unordered_map>
 
index 44ebc05..cf151ba 100644 (file)
@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include "LayerVisitorBase.hpp"
+#include "armnn/LayerVisitorBase.hpp"
 #include "StaticRangeVisitor.hpp"
 
 #include <armnn/INetwork.hpp>
index 9c3a4f3..d834d04 100644 (file)
@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include "LayerVisitorBase.hpp"
+#include "armnn/LayerVisitorBase.hpp"
 
 #include <armnn/INetwork.hpp>
 #include <armnn/INetworkQuantizer.hpp>
index c83d179..24c130c 100644 (file)
@@ -8,7 +8,7 @@
 #include <armnn/INetworkQuantizer.hpp>
 #include <armnn/Types.hpp>
 
-#include "../LayerVisitorBase.hpp"
+#include "armnn/LayerVisitorBase.hpp"
 #include "../Network.hpp"
 #include "../Graph.hpp"
 #include "../NetworkQuantizerUtils.hpp"
index ca2e7e3..5ba92d5 100644 (file)
@@ -226,7 +226,7 @@ DeserializeParser::LayerBaseRawPtrVector DeserializeParser::GetGraphInputs(const
 
     for (unsigned int i=0; i<numInputs; ++i)
     {
-        uint32_t inputId = CHECKED_NON_NEGATIVE(graphPtr->inputIds()->Get(i));
+        uint32_t inputId = graphPtr->inputIds()->Get(i);
         result[i] = GetBaseLayer(graphPtr, static_cast<uint32_t>(inputId));
     }
     return result;
@@ -241,7 +241,7 @@ DeserializeParser::LayerBaseRawPtrVector DeserializeParser::GetGraphOutputs(cons
 
     for (unsigned int i=0; i<numOutputs; ++i)
     {
-        uint32_t outputId = CHECKED_NON_NEGATIVE(graphPtr->outputIds()->Get(i));
+        uint32_t outputId = graphPtr->outputIds()->Get(i);
         result[i] = GetBaseLayer(graphPtr, static_cast<uint32_t>(outputId));
     }
     return result;
diff --git a/src/armnnSerializer/README.md b/src/armnnSerializer/README.md
new file mode 100644 (file)
index 0000000..61478b1
--- /dev/null
@@ -0,0 +1,6 @@
+# The Arm NN Serializer
+
+The `armnnSerializer` is a library for serializing an Arm NN network to a stream.
+
+For more information about the layers that are supported, and the networks that have been tested,
+see [SerializerSupport.md](./SerializerSupport.md)
index 2a5fbcd..2527f6d 100644 (file)
@@ -108,8 +108,8 @@ table AnyLayer {
 // Root type for serialized data is the graph of the network
 table SerializedGraph {
     layers:[AnyLayer];
-    inputIds:[int];
-    outputIds:[int];
+    inputIds:[uint];
+    outputIds:[uint];
 }
 
 root_type SerializedGraph;
diff --git a/src/armnnSerializer/SeralizerSupport.md b/src/armnnSerializer/SeralizerSupport.md
new file mode 100644 (file)
index 0000000..16d1940
--- /dev/null
@@ -0,0 +1,11 @@
+# The layers that ArmNN SDK Serializer currently supports.
+
+This reference guide provides a list of layers which can be serialized currently by the Arm NN SDK.
+
+## Fully supported
+
+The Arm NN SDK Serializer currently supports the following layers:
+
+* Addition
+
+More machine learning layers will be supported in future releases.
\ No newline at end of file
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
new file mode 100644 (file)
index 0000000..57baf0e
--- /dev/null
@@ -0,0 +1,186 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "Serializer.hpp"
+#include <armnn/ArmNN.hpp>
+#include <iostream>
+#include <Schema_generated.h>
+#include <flatbuffers/util.h>
+
+using namespace armnn;
+namespace fb = flatbuffers;
+namespace serializer = armnn::armnnSerializer;
+
+namespace armnnSerializer
+{
+
+serializer::DataType GetFlatBufferDataType(DataType dataType)
+{
+    switch (dataType)
+    {
+        case DataType::Float32:
+            return serializer::DataType::DataType_Float32;
+        case DataType::Float16:
+            return serializer::DataType::DataType_Float16;
+        case DataType::Signed32:
+            return serializer::DataType::DataType_Signed32;
+        case DataType::QuantisedAsymm8:
+            return serializer::DataType::DataType_QuantisedAsymm8;
+        case DataType::Boolean:
+            return serializer::DataType::DataType_Boolean;
+        default:
+            return serializer::DataType::DataType_Float16;
+    }
+}
+
+// Build FlatBuffer for Input Layer
+void Serializer::VisitInputLayer(const IConnectableLayer* layer, LayerBindingId id, const char* name)
+{
+    // Create FlatBuffer BaseLayer
+    auto flatBufferInputBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Input);
+
+    // Create FlatBuffer BindableBaseLayer
+    auto flatBufferInputBindableBaseLayer = serializer::CreateBindableLayerBase(m_flatBufferBuilder,
+                                                                                flatBufferInputBaseLayer,
+                                                                                id);
+
+    // Push layer Guid to outputIds.
+    m_inputIds.push_back(layer->GetGuid());
+
+    // Create the FlatBuffer InputLayer
+    auto flatBufferInputLayer = serializer::CreateInputLayer(m_flatBufferBuilder, flatBufferInputBindableBaseLayer);
+
+    // Add the AnyLayer to the FlatBufferLayers
+    CreateAnyLayer(flatBufferInputLayer.o, serializer::Layer::Layer_InputLayer);
+}
+
+// Build FlatBuffer for Output Layer
+void Serializer::VisitOutputLayer(const IConnectableLayer* layer, LayerBindingId id, const char* name)
+{
+    // Create FlatBuffer BaseLayer
+    auto flatBufferOutputBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Output);
+
+    // Create FlatBuffer BindableBaseLayer
+    auto flatBufferOutputBindableBaseLayer = serializer::CreateBindableLayerBase(m_flatBufferBuilder,
+                                                                                 flatBufferOutputBaseLayer,
+                                                                                 id);
+    // Push layer Guid to outputIds.
+    m_outputIds.push_back(layer->GetGuid());
+
+    // Create the FlatBuffer OutputLayer
+    auto flatBufferOutputLayer = serializer::CreateOutputLayer(m_flatBufferBuilder, flatBufferOutputBindableBaseLayer);
+    // Add the AnyLayer to the FlatBufferLayers
+    CreateAnyLayer(flatBufferOutputLayer.o, serializer::Layer::Layer_OutputLayer);
+}
+
+// Build FlatBuffer for Addition Layer
+void Serializer::VisitAdditionLayer(const IConnectableLayer* layer, const char* name)
+{
+    // Create FlatBuffer BaseLayer
+    auto flatBufferAdditionBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Addition);
+
+    // Create the FlatBuffer AdditionLayer
+    auto flatBufferAdditionLayer = serializer::CreateAdditionLayer(m_flatBufferBuilder, flatBufferAdditionBaseLayer);
+
+    // Add the AnyLayer to the FlatBufferLayers
+    CreateAnyLayer(flatBufferAdditionLayer.o, serializer::Layer::Layer_AdditionLayer);
+}
+
+void Serializer::Serialize(const INetwork& inNetwork)
+{
+    // Iterate through to network
+    inNetwork.Accept(*this);
+
+    // Create FlatBuffer SerializedGraph
+    auto serializedGraph = serializer::CreateSerializedGraph(m_flatBufferBuilder,
+                                                             m_flatBufferBuilder.CreateVector(m_serializedLayers),
+                                                             m_flatBufferBuilder.CreateVector(m_inputIds),
+                                                             m_flatBufferBuilder.CreateVector(m_outputIds));
+
+    // Serialize the graph
+    m_flatBufferBuilder.Finish(serializedGraph);
+}
+
+bool Serializer::SaveSerializedToStream(std::ostream& stream)
+{
+    stream.write(reinterpret_cast<const char*>(m_flatBufferBuilder.GetBufferPointer()), m_flatBufferBuilder.GetSize());
+    return !stream.bad();
+}
+
+fb::Offset<serializer::LayerBase> Serializer::CreateLayerBase(const IConnectableLayer* layer,
+                                                              const serializer::LayerType layerType)
+{
+    std::vector<fb::Offset<serializer::InputSlot>> inputSlots = CreateInputSlots(layer);
+    std::vector<fb::Offset<serializer::OutputSlot>> outputSlots = CreateOutputSlots(layer);
+
+    return serializer::CreateLayerBase(m_flatBufferBuilder,
+                                       layer->GetGuid(),
+                                       m_flatBufferBuilder.CreateString(layer->GetName()),
+                                       layerType,
+                                       m_flatBufferBuilder.CreateVector(inputSlots),
+                                       m_flatBufferBuilder.CreateVector(outputSlots));
+}
+
+void Serializer::CreateAnyLayer(const flatbuffers::Offset<void>& layer, const serializer::Layer serializerLayer)
+{
+    auto anyLayer = armnn::armnnSerializer::CreateAnyLayer(m_flatBufferBuilder,
+                                                           serializerLayer,
+                                                           layer);
+    m_serializedLayers.push_back(anyLayer);
+}
+
+std::vector<fb::Offset<serializer::InputSlot>> Serializer::CreateInputSlots(const IConnectableLayer* layer)
+{
+    std::vector<fb::Offset <serializer::InputSlot>> inputSlots;
+
+    // Get the InputSlots
+    for (unsigned int slotIndex = 0; slotIndex<layer->GetNumInputSlots(); ++slotIndex)
+    {
+        const IInputSlot& inputSlot = layer->GetInputSlot(slotIndex);
+
+        // Get the Connection for the InputSlot
+        const IOutputSlot* connection = inputSlot.GetConnection();
+
+        // Create FlatBuffer Connection
+        serializer::Connection conn(connection->GetOwningLayerGuid(), connection->CalculateIndexOnOwner());
+        // Create FlatBuffer InputSlot
+        inputSlots.push_back(serializer::CreateInputSlot(m_flatBufferBuilder, slotIndex, &conn));
+    }
+    return inputSlots;
+}
+
+std::vector<fb::Offset<serializer::OutputSlot>> Serializer::CreateOutputSlots(const IConnectableLayer* layer)
+{
+    std::vector<fb::Offset<serializer::OutputSlot>> outputSlots;
+
+    // Get the OutputSlots
+    for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
+    {
+        const IOutputSlot& outputSlot = layer->GetOutputSlot(slotIndex);
+        const TensorInfo& tensorInfo = outputSlot.GetTensorInfo();
+
+        // Get the dimensions
+        std::vector<unsigned int> shape;
+        for(unsigned int dim = 0; dim < tensorInfo.GetShape().GetNumDimensions(); ++dim)
+        {
+            shape.push_back(tensorInfo.GetShape()[dim]);
+        }
+
+        // Create FlatBuffer TensorInfo
+        auto flatBufferTensorInfo = serializer::CreateTensorInfo(m_flatBufferBuilder,
+                                                                 m_flatBufferBuilder.CreateVector(shape),
+                                                                 GetFlatBufferDataType(tensorInfo.GetDataType()),
+                                                                 tensorInfo.GetQuantizationScale(),
+                                                                 tensorInfo.GetQuantizationOffset());
+
+        // Create FlatBuffer Outputslot
+        outputSlots.push_back(serializer::CreateOutputSlot(m_flatBufferBuilder,
+                                                           slotIndex,
+                                                           flatBufferTensorInfo));
+    }
+    return outputSlots;
+}
+
+} //namespace armnnSerializer
diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp
new file mode 100644 (file)
index 0000000..697e5cf
--- /dev/null
@@ -0,0 +1,72 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnn/ILayerVisitor.hpp>
+#include <armnn/LayerVisitorBase.hpp>
+#include <iostream>
+#include <Schema_generated.h>
+
+namespace armnnSerializer
+{
+
+class Serializer : public armnn::LayerVisitorBase<armnn::VisitorNoThrowPolicy>
+{
+public:
+    Serializer() {};
+    ~Serializer() {};
+
+    void VisitAdditionLayer(const armnn::IConnectableLayer* layer,
+                            const char* name = nullptr) override;
+
+    void VisitInputLayer(const armnn::IConnectableLayer* layer,
+                         armnn::LayerBindingId id,
+                         const char* name = nullptr) override;
+
+    void VisitOutputLayer(const armnn::IConnectableLayer* layer,
+                          armnn::LayerBindingId id,
+                          const char* name = nullptr) override;
+
+    /// Serializes the network to ArmNN SerializedGraph.
+    /// @param [in] inNetwork The network to be serialized.
+    void Serialize(const armnn::INetwork& inNetwork);
+
+    /// Serializes the SerializedGraph to the stream.
+    /// @param [stream] the stream to save to
+    /// @return true if graph is Serialized to the Stream, false otherwise
+    bool SaveSerializedToStream(std::ostream& stream);
+
+private:
+
+    /// Creates the Input Slots and Output Slots and LayerBase for the layer.
+    flatbuffers::Offset<armnn::armnnSerializer::LayerBase> CreateLayerBase(
+            const armnn::IConnectableLayer* layer,
+            const armnn::armnnSerializer::LayerType layerType);
+
+    /// Creates the serializer AnyLayer for the layer and adds it to m_serializedLayers.
+    void CreateAnyLayer(const flatbuffers::Offset<void>& layer, const armnn::armnnSerializer::Layer serializerLayer);
+
+    /// Creates the serializer InputSlots for the layer.
+    std::vector<flatbuffers::Offset<armnn::armnnSerializer::InputSlot>> CreateInputSlots(
+            const armnn::IConnectableLayer* layer);
+
+    /// Creates the serializer OutputSlots for the layer.
+    std::vector<flatbuffers::Offset<armnn::armnnSerializer::OutputSlot>> CreateOutputSlots(
+            const armnn::IConnectableLayer* layer);
+
+    /// FlatBufferBuilder to create our layers' FlatBuffers.
+    flatbuffers::FlatBufferBuilder m_flatBufferBuilder;
+
+    /// AnyLayers required by the SerializedGraph.
+    std::vector<flatbuffers::Offset<armnn::armnnSerializer::AnyLayer>> m_serializedLayers;
+
+    /// Guids of all Input Layers required by the SerializedGraph.
+    std::vector<unsigned int> m_inputIds;
+
+    /// Guids of all Output Layers required by the SerializedGraph.
+    std::vector<unsigned int> m_outputIds;
+};
+
+} //namespace armnnSerializer
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
new file mode 100644 (file)
index 0000000..17ad6e3
--- /dev/null
@@ -0,0 +1,35 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <armnn/ArmNN.hpp>
+#include <armnn/INetwork.hpp>
+#include "../Serializer.hpp"
+#include <sstream>
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(SerializerTests)
+
+BOOST_AUTO_TEST_CASE(SimpleNetworkSerialization)
+{
+    armnn::INetworkPtr network = armnn::INetwork::Create();
+    armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0);
+    armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1);
+
+    armnn::IConnectableLayer* const additionLayer0 = network->AddAdditionLayer();
+    inputLayer0->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(0));
+    inputLayer1->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(1));
+
+    armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0);
+    additionLayer0->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0));
+
+    armnnSerializer::Serializer serializer;
+    serializer.Serialize(*network);
+
+    std::stringstream stream;
+    serializer.SaveSerializedToStream(stream);
+    BOOST_TEST(stream.str().length() > 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()