IVGCVSW-4271 Add getSupportedOperations marker file

* Also fix segfault in previous graph dump code
* Cherry picked from 19.08 (https://jira.arm.com/browse/IVGCVSW-4297)

Change-Id: Id4f2e89f5126b7962b4439370e6dd3edcee96f51
Signed-off-by: Jim Flynn <jim.flynn@arm.com>
diff --git a/1.2/ArmnnDriver.hpp b/1.2/ArmnnDriver.hpp
index 40116c8..177cab6 100644
--- a/1.2/ArmnnDriver.hpp
+++ b/1.2/ArmnnDriver.hpp
@@ -119,7 +119,7 @@
 
     Return<void> getVersionString(getVersionString_cb cb)
     {
-        ALOGV("hal_1_2::ArmnnDriver::getSupportedOperations()");
+        ALOGV("hal_1_2::ArmnnDriver::getVersionString()");
 
         cb(ErrorStatus::NONE, "ArmNN");
         return Void();
diff --git a/1.2/ArmnnDriverImpl.cpp b/1.2/ArmnnDriverImpl.cpp
index dfb77c3..136228f 100644
--- a/1.2/ArmnnDriverImpl.cpp
+++ b/1.2/ArmnnDriverImpl.cpp
@@ -161,8 +161,8 @@
 
     // Export the optimized network graph to a dot file if an output dump directory
     // has been specified in the drivers' arguments.
-    ExportNetworkGraphToDotFile<hal_1_2::HalPolicy::Model>(*optNet, options.GetRequestInputsAndOutputsDumpDir(),
-            model);
+    std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet,
+                                                               options.GetRequestInputsAndOutputsDumpDir());
 
     // Load it into the runtime.
     armnn::NetworkId netId = 0;
@@ -181,6 +181,12 @@
         return ErrorStatus::NONE;
     }
 
+    // Now that we have a networkId for the graph rename the dump file to use it
+    // so that we can associate the graph file and the input/output tensor dump files
+    RenameGraphDotFile(dotGraphFileName,
+                       options.GetRequestInputsAndOutputsDumpDir(),
+                       netId);
+
     std::unique_ptr<ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>> preparedModel(
             new ArmnnPreparedModel_1_2<hal_1_2::HalPolicy>(
                     netId,
diff --git a/ArmnnDriverImpl.cpp b/ArmnnDriverImpl.cpp
index 46c4e57..cbb2e64 100644
--- a/ArmnnDriverImpl.cpp
+++ b/ArmnnDriverImpl.cpp
@@ -131,7 +131,7 @@
 
     // Export the optimized network graph to a dot file if an output dump directory
     // has been specified in the drivers' arguments.
-    ExportNetworkGraphToDotFile<HalModel>(*optNet, options.GetRequestInputsAndOutputsDumpDir(), model);
+    std::string dotGraphFileName = ExportNetworkGraphToDotFile(*optNet, options.GetRequestInputsAndOutputsDumpDir());
 
     // Load it into the runtime.
     armnn::NetworkId netId = 0;
@@ -150,7 +150,13 @@
         return ErrorStatus::NONE;
     }
 
-    sp<ArmnnPreparedModel<HalPolicy>> preparedModel(
+    // Now that we have a networkId for the graph rename the dump file to use it
+    // so that we can associate the graph file and the input/output tensor dump files
+    RenameGraphDotFile(dotGraphFileName,
+                       options.GetRequestInputsAndOutputsDumpDir(),
+                       netId);
+
+    unique_ptr<ArmnnPreparedModel<HalPolicy>> preparedModel(
             new ArmnnPreparedModel<HalPolicy>(
                     netId,
                     runtime.get(),
@@ -180,7 +186,7 @@
         }
     }
 
-    NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel);
+    NotifyCallbackAndCheck(cb, ErrorStatus::NONE, preparedModel.release());
 
     return ErrorStatus::NONE;
 }
@@ -191,7 +197,31 @@
                                                                 const HalModel& model,
                                                                 HalGetSupportedOperations_cb cb)
 {
-    ALOGV("ArmnnDriverImpl::getSupportedOperations()");
+    std::stringstream ss;
+    ss << "ArmnnDriverImpl::getSupportedOperations()";
+    std::string fileName;
+    std::string timestamp;
+    if (!options.GetRequestInputsAndOutputsDumpDir().empty())
+    {
+        timestamp = GetFileTimestamp();
+        fileName = boost::str(boost::format("%1%/%2%_getSupportedOperations.txt")
+                          % options.GetRequestInputsAndOutputsDumpDir()
+                          % timestamp);
+        ss << " : " << fileName;
+    }
+    ALOGV(ss.str().c_str());
+
+    if (!options.GetRequestInputsAndOutputsDumpDir().empty())
+    {
+        //dump the marker file
+        std::ofstream fileStream;
+        fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
+        if (fileStream.good())
+        {
+            fileStream << timestamp << std::endl;
+        }
+        fileStream.close();
+    }
 
     vector<bool> result;
 
diff --git a/Utils.cpp b/Utils.cpp
index 229f35b..49a4c79 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -11,7 +11,13 @@
 #include <Permute.hpp>
 
 #include <cassert>
+#include <cerrno>
 #include <cinttypes>
+#include <sstream>
+#include <cstdio>
+#include <time.h>
+
+
 
 using namespace android;
 using namespace android::hardware;
@@ -246,6 +252,11 @@
             dumpElementFunction = &DumpTensorElement<int32_t>;
             break;
         }
+        case armnn::DataType::Float16:
+        {
+            dumpElementFunction = &DumpTensorElement<armnn::Half>;
+            break;
+        }
         default:
         {
             dumpElementFunction = nullptr;
@@ -358,10 +369,91 @@
     profiler->Print(fileStream);
 }
 
+std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork,
+                                        const std::string& dumpDir)
+{
+    std::string fileName;
+    // The dump directory must exist in advance.
+    if (dumpDir.empty())
+    {
+        return fileName;
+    }
+
+    std::string timestamp = GetFileTimestamp();
+    if (timestamp.empty())
+    {
+        return fileName;
+    }
+
+    // Set the name of the output .dot file.
+    fileName = boost::str(boost::format("%1%/%2%_networkgraph.dot")
+                          % dumpDir
+                          % timestamp);
+
+    ALOGV("Exporting the optimized network graph to file: %s", fileName.c_str());
+
+    // Write the network graph to a dot file.
+    std::ofstream fileStream;
+    fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
+
+    if (!fileStream.good())
+    {
+        ALOGW("Could not open file %s for writing", fileName.c_str());
+        return fileName;
+    }
+
+    if (optimizedNetwork.SerializeToDot(fileStream) != armnn::Status::Success)
+    {
+        ALOGW("An error occurred when writing to file %s", fileName.c_str());
+    }
+    return fileName;
+}
+
 bool IsDynamicTensor(const armnn::TensorInfo& outputInfo)
 {
     // Dynamic tensors have at least one 0-sized dimension
     return outputInfo.GetNumElements() == 0u;
 }
 
+std::string GetFileTimestamp()
+{
+    // used to get a timestamp to name diagnostic files (the ArmNN serialized graph
+    // and getSupportedOperations.txt files)
+    timespec ts;
+    int iRet = clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+    std::stringstream ss;
+    if (iRet == 0)
+    {
+        ss << std::to_string(ts.tv_sec) << "_" << std::to_string(ts.tv_nsec);
+    }
+    else
+    {
+        ALOGW("clock_gettime failed with errno %s : %s", std::to_string(errno).c_str(), std::strerror(errno));
+    }
+    return ss.str();
+}
+
+void RenameGraphDotFile(const std::string& oldName, const std::string& dumpDir, const armnn::NetworkId networkId)
+{
+    if (dumpDir.empty())
+    {
+        return;
+    }
+    if (oldName.empty())
+    {
+        return;
+    }
+    const std::string newFileName = boost::str(boost::format("%1%/%2%_networkgraph.dot")
+                                               % dumpDir
+                                               % std::to_string(networkId));
+    int iRet = rename(oldName.c_str(), newFileName.c_str());
+    if (iRet != 0)
+    {
+        std::stringstream ss;
+        ss << "rename of [" << oldName << "] to [" << newFileName << "] failed with errno " << std::to_string(errno)
+           << " : " << std::strerror(errno);
+        ALOGW(ss.str().c_str());
+    }
+}
+
 } // namespace armnn_driver
diff --git a/Utils.hpp b/Utils.hpp
index 267e519..c5a2e65 100644
--- a/Utils.hpp
+++ b/Utils.hpp
@@ -104,47 +104,14 @@
                                  armnn::NetworkId networkId,
                                  const armnn::IProfiler* profiler);
 
-template <typename HalModel>
-void ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork,
-                                 const std::string& dumpDir,
-                                 const HalModel& model)
-{
-    // The dump directory must exist in advance.
-    if (dumpDir.empty())
-    {
-        return;
-    }
+std::string ExportNetworkGraphToDotFile(const armnn::IOptimizedNetwork& optimizedNetwork,
+                                        const std::string& dumpDir);
 
-    // Get the memory address of the model and convert it to a hex string (of at least a '0' character).
-    size_t modelAddress = uintptr_t(&model);
-    std::stringstream ss;
-    ss << std::uppercase << std::hex << std::setfill('0') << std::setw(1) << modelAddress;
-    std::string modelAddressHexString = ss.str();
-
-    // Set the name of the output .dot file.
-    const std::string fileName = boost::str(boost::format("%1%/networkgraph_%2%.dot")
-                                            % dumpDir
-                                            % modelAddressHexString);
-
-    ALOGV("Exporting the optimized network graph to file: %s", fileName.c_str());
-
-    // Write the network graph to a dot file.
-    std::ofstream fileStream;
-    fileStream.open(fileName, std::ofstream::out | std::ofstream::trunc);
-
-    if (!fileStream.good())
-    {
-        ALOGW("Could not open file %s for writing", fileName.c_str());
-        return;
-    }
-
-    if (optimizedNetwork.SerializeToDot(fileStream) != armnn::Status::Success)
-    {
-        ALOGW("An error occurred when writing to file %s", fileName.c_str());
-    }
-}
+void RenameGraphDotFile(const std::string& oldName, const std::string& dumpDir, const armnn::NetworkId networkId);
 
 /// Checks if a tensor info represents a dynamic tensor
 bool IsDynamicTensor(const armnn::TensorInfo& outputInfo);
 
+std::string GetFileTimestamp();
+
 } // namespace armnn_driver
diff --git a/test/UtilsTests.cpp b/test/UtilsTests.cpp
index f337db7..a11c827 100644
--- a/test/UtilsTests.cpp
+++ b/test/UtilsTests.cpp
@@ -35,20 +35,16 @@
     {}
     ExportNetworkGraphFixture(const std::string& requestInputsAndOutputsDumpDir)
         : m_RequestInputsAndOutputsDumpDir(requestInputsAndOutputsDumpDir)
-        , m_Model({})
         , m_FileName()
         , m_FileStream()
     {
-        // Get the memory address of the model and convert it to a hex string (of at least a '0' character).
-        size_t modelAddress = uintptr_t(&m_Model);
-        std::stringstream ss;
-        ss << std::uppercase << std::hex << std::setfill('0') << std::setw(1) << modelAddress;
-        std::string modelAddressHexString = ss.str();
-
         // Set the name of the output .dot file.
-        m_FileName = boost::str(boost::format("%1%/networkgraph_%2%.dot")
+        // NOTE: the export now uses a time stamp to name the file so we
+        //       can't predict ahead of time what the file name will be.
+        std::string timestamp = "dummy";
+        m_FileName = boost::str(boost::format("%1%/%2%_networkgraph.dot")
                                 % m_RequestInputsAndOutputsDumpDir
-                                % modelAddressHexString);
+                                % timestamp);
     }
 
     // Teardown: delete the dump file regardless of the outcome of the tests.
@@ -69,6 +65,11 @@
             m_FileStream.close();
         }
 
+        if (m_FileName.empty())
+        {
+            return false;
+        }
+
         // Open the file.
         m_FileStream.open(m_FileName, std::ifstream::in);
 
@@ -96,10 +97,9 @@
     }
 
     std::string m_RequestInputsAndOutputsDumpDir;
-    V1_0::Model m_Model;
+    std::string m_FileName;
 
 private:
-    std::string m_FileName;
     std::ifstream m_FileStream;
 };
 
@@ -144,9 +144,8 @@
     MockOptimizedNetwork mockOptimizedNetwork(mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture.m_RequestInputsAndOutputsDumpDir,
-                                              fixture.m_Model);
+    fixture.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture.m_RequestInputsAndOutputsDumpDir);
 
     // Check that the output file does not exist.
     BOOST_TEST(!fixture.FileExists());
@@ -164,9 +163,8 @@
     MockOptimizedNetwork mockOptimizedNetwork(mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture.m_RequestInputsAndOutputsDumpDir,
-                                              fixture.m_Model);
+    fixture.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture.m_RequestInputsAndOutputsDumpDir);
 
     // Check that the output file exists and that it has the correct name.
     BOOST_TEST(fixture.FileExists());
@@ -187,9 +185,8 @@
     MockOptimizedNetwork mockOptimizedNetwork(mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture.m_RequestInputsAndOutputsDumpDir,
-                                              fixture.m_Model);
+    fixture.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture.m_RequestInputsAndOutputsDumpDir);
 
     // Check that the output file exists and that it has the correct name.
     BOOST_TEST(fixture.FileExists());
@@ -202,9 +199,8 @@
     mockOptimizedNetwork.UpdateMockSerializedContent(mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture.m_RequestInputsAndOutputsDumpDir,
-                                              fixture.m_Model);
+    fixture.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture.m_RequestInputsAndOutputsDumpDir);
 
     // Check that the output file still exists and that it has the correct name.
     BOOST_TEST(fixture.FileExists());
@@ -227,9 +223,8 @@
     MockOptimizedNetwork mockOptimizedNetwork(mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture1.m_RequestInputsAndOutputsDumpDir,
-                                              fixture1.m_Model);
+    fixture1.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture1.m_RequestInputsAndOutputsDumpDir);
 
     // Check that the output file exists and that it has the correct name.
     BOOST_TEST(fixture1.FileExists());
@@ -238,9 +233,8 @@
     BOOST_TEST(fixture1.GetFileContent() == mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture2.m_RequestInputsAndOutputsDumpDir,
-                                              fixture2.m_Model);
+    fixture2.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture2.m_RequestInputsAndOutputsDumpDir);
 
     // Check that the output file exists and that it has the correct name.
     BOOST_TEST(fixture2.FileExists());
@@ -249,9 +243,8 @@
     BOOST_TEST(fixture2.GetFileContent() == mockSerializedContent);
 
     // Export the mock optimized network.
-    armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
-                                              fixture3.m_RequestInputsAndOutputsDumpDir,
-                                              fixture3.m_Model);
+    fixture3.m_FileName = armnn_driver::ExportNetworkGraphToDotFile(mockOptimizedNetwork,
+                                              fixture3.m_RequestInputsAndOutputsDumpDir);
     // Check that the output file exists and that it has the correct name.
     BOOST_TEST(fixture3.FileExists());