aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Tello <pablo.tello@arm.com>2018-10-24 15:32:39 +0100
committerGeorgios Pinitas <georgios.pinitas@arm.com>2018-11-09 17:04:04 +0000
commit0cf77981fadb883b97efec112e115450873e64c3 (patch)
tree42592f5dd8721ab8337059df3861e1e2b849399d
parent283fc606dbd9058f636b91350a1c47b97aba1a87 (diff)
downloadComputeLibrary-0cf77981fadb883b97efec112e115450873e64c3.tar.gz
COMPMID-1626: Fixed VGG 16/19 bad_alloc failure.
Some systems don't have enough memory to run the VGG networks, for example on systems with only 2GB memory the VGG example fails throwing a bad_alloc exception. This patch introduces the concept of global memory policy in ACL, the policy is a mechanism which could be used by the library's functions to try to reduce memory consumption on systems with limited memory. In this specific case the VGG examples set the policy to MINIMIZE. The GEMM function checks if the policy is MINIMIZE and in this case does not use the pretransposed weights path as this requires considerable more memory. Change-Id: I53abc3c9c64d045d8306793ffc9d24b28e228b7b
-rw-r--r--arm_compute/core/CPP/CPPTypes.h41
-rw-r--r--arm_compute/core/Types.h4
-rw-r--r--examples/graph_vgg16.cpp10
-rw-r--r--examples/graph_vgg19.cpp10
-rw-r--r--src/runtime/MEMUtils.cpp111
-rw-r--r--src/runtime/NEON/functions/NEGEMM.cpp9
6 files changed, 182 insertions, 3 deletions
diff --git a/arm_compute/core/CPP/CPPTypes.h b/arm_compute/core/CPP/CPPTypes.h
index 9ffb4840a3..0ac8bf6e52 100644
--- a/arm_compute/core/CPP/CPPTypes.h
+++ b/arm_compute/core/CPP/CPPTypes.h
@@ -26,6 +26,7 @@
#include "arm_compute/core/Error.h"
+#include <array>
#include <string>
#include <vector>
@@ -46,6 +47,19 @@ enum class CPUModel
A55r1
};
+/** Global memory policy.
+ * The functions in the runtime will use different strategies based on the policy currently set.
+ *
+ * MINIMIZE will try to reduce the amount allocated by the functions at the expense of performance normally.
+ * NORMAL won't try to save any memory and will favor speed over memory consumption
+ *
+ */
+enum class MemoryPolicy
+{
+ MINIMIZE,
+ NORMAL
+};
+
/** Convert a cpumodel value to a string
*
* @param val CPUModel value to be converted
@@ -180,6 +194,33 @@ private:
unsigned int _L2_cache_size = 262144;
};
+class MEMInfo final
+{
+public:
+ MEMInfo();
+
+ /** Return the total amount of RAM memory in the system expressed in KB.
+ *
+ * @return Total memory
+ */
+ size_t get_total_in_kb() const;
+
+ static void set_policy(MemoryPolicy policy);
+ static MemoryPolicy get_policy();
+
+ /** Common memory sizes expressed in Kb to avoid having them
+ * duplicated throughout the code.
+ */
+ static const size_t ONE_GB_IN_KB = { 1035842 };
+ static const size_t TWO_GB_IN_KB = { ONE_GB_IN_KB * 2 };
+
+private:
+ size_t _total;
+ size_t _free;
+ size_t _buffer;
+ static MemoryPolicy _policy;
+};
+
/** Information about executing thread and CPU. */
struct ThreadInfo
{
diff --git a/arm_compute/core/Types.h b/arm_compute/core/Types.h
index 0240916da8..8df5c65e1e 100644
--- a/arm_compute/core/Types.h
+++ b/arm_compute/core/Types.h
@@ -940,8 +940,8 @@ public:
* @param[in] weights (Optional)Weights [wx, wy, ww, wh] for the deltas. Defaults to all ones
* @param[in] bbox_xform_clip (Optional)Minimum bounding box width and height after bounding box transformation in log-space. Defaults to log(1000/16)
*/
- BoundingBoxTransformInfo(float img_width, float img_height, float scale, bool apply_scale = false, const std::array<float, 4> weights = { 1.0, 1.0, 1.0, 1.0 }, float bbox_xform_clip =
- 4.135166556742356)
+ BoundingBoxTransformInfo(float img_width, float img_height, float scale, bool apply_scale = false, const std::array<float, 4> weights = { { 1.f, 1.f, 1.f, 1.f } }, float bbox_xform_clip =
+ 4.135166556742356f)
: _img_width(img_width), _img_height(img_height), _scale(scale), _apply_scale(apply_scale), _weights(weights), _bbox_xform_clip(bbox_xform_clip)
{
}
diff --git a/examples/graph_vgg16.cpp b/examples/graph_vgg16.cpp
index 4b5f33a7e8..482aab1683 100644
--- a/examples/graph_vgg16.cpp
+++ b/examples/graph_vgg16.cpp
@@ -41,6 +41,16 @@ public:
}
bool do_setup(int argc, char **argv) override
{
+ // Check if the system has enough RAM to run the example, systems with less than 2GB have
+ // to hint the API to minimize memory consumption otherwise it'll run out of memory and
+ // fail throwing the bad_alloc exception
+ arm_compute::MEMInfo meminfo;
+ const size_t mem_total = meminfo.get_total_in_kb();
+ if(mem_total <= arm_compute::MEMInfo::TWO_GB_IN_KB)
+ {
+ arm_compute::MEMInfo::set_policy(arm_compute::MemoryPolicy::MINIMIZE);
+ }
+
// Parse arguments
cmd_parser.parse(argc, argv);
diff --git a/examples/graph_vgg19.cpp b/examples/graph_vgg19.cpp
index ff7cf751a1..3b1773519a 100644
--- a/examples/graph_vgg19.cpp
+++ b/examples/graph_vgg19.cpp
@@ -40,6 +40,16 @@ public:
}
bool do_setup(int argc, char **argv) override
{
+ // Check if the system has enough RAM to run the example, systems with less than 2GB have
+ // to hint the API to minimize memory consumption otherwise it'll run out of memory and
+ // fail throwing the bad_alloc exception
+ arm_compute::MEMInfo meminfo;
+ const size_t mem_total = meminfo.get_total_in_kb();
+ if(mem_total <= arm_compute::MEMInfo::TWO_GB_IN_KB)
+ {
+ arm_compute::MEMInfo::set_policy(arm_compute::MemoryPolicy::MINIMIZE);
+ }
+
// Parse arguments
cmd_parser.parse(argc, argv);
diff --git a/src/runtime/MEMUtils.cpp b/src/runtime/MEMUtils.cpp
new file mode 100644
index 0000000000..ad00070935
--- /dev/null
+++ b/src/runtime/MEMUtils.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * 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.
+ */
+#include "arm_compute/core/CPP/CPPTypes.h"
+#include "arm_compute/core/Error.h"
+#include "support/ToolchainSupport.h"
+
+#ifndef BARE_METAL
+#include <fstream>
+#include <regex>
+#include <sstream>
+#endif // ifndef BARE_METAL
+
+namespace
+{
+void parse_mem_info(size_t &total, size_t &free, size_t &buffer)
+{
+ free = 0;
+ total = 0;
+ buffer = 0;
+#ifndef BARE_METAL
+ size_t memcache = 0;
+ size_t memfree = 0;
+ std::ifstream meminfo_f;
+ meminfo_f.open("/proc/meminfo", std::ios::in);
+ if(meminfo_f.is_open())
+ {
+ std::stringstream str_stream;
+ str_stream << meminfo_f.rdbuf();
+ const std::string str = str_stream.str();
+ try
+ {
+ std::smatch match;
+ if(std::regex_search(str, match, std::regex("MemTotal: (.*)kB")) && match.size() > 1)
+ {
+ const std::string result = match.str(1);
+ total = std::stoul(result, nullptr, 0);
+ }
+ if(std::regex_search(str, match, std::regex("MemFree: (.*)kB")) && match.size() > 1)
+ {
+ const std::string result = match.str(1);
+ memfree = std::stoul(result, nullptr, 0);
+ }
+ if(std::regex_search(str, match, std::regex("Buffers: (.*)kB")) && match.size() > 1)
+ {
+ const std::string result = match.str(1);
+ buffer = std::stoul(result, nullptr, 0);
+ }
+ if(std::regex_search(str, match, std::regex("Cached: (.*)kB")) && match.size() > 1)
+ {
+ const std::string result = match.str(1);
+ memcache = std::stoul(result, nullptr, 0);
+ }
+ free = memfree + (buffer + memcache);
+ }
+ catch(std::regex_error &e)
+ {
+ // failed parsing /proc/meminfo
+ // return 0s on all fields
+ }
+ }
+#endif // ifndef BARE_METAL
+}
+
+} // namespace
+
+namespace arm_compute
+{
+void MEMInfo::set_policy(MemoryPolicy policy)
+{
+ _policy = policy;
+}
+
+MemoryPolicy MEMInfo::get_policy()
+{
+ return _policy;
+}
+MemoryPolicy MEMInfo::_policy = { MemoryPolicy::NORMAL };
+
+MEMInfo::MEMInfo()
+ : _total(0), _free(0), _buffer(0)
+{
+ parse_mem_info(_total, _free, _buffer);
+}
+
+size_t MEMInfo::get_total_in_kb() const
+{
+ return _total;
+}
+
+} // namespace arm_compute
diff --git a/src/runtime/NEON/functions/NEGEMM.cpp b/src/runtime/NEON/functions/NEGEMM.cpp
index e8bf6732b2..82b9cb80ae 100644
--- a/src/runtime/NEON/functions/NEGEMM.cpp
+++ b/src/runtime/NEON/functions/NEGEMM.cpp
@@ -62,7 +62,14 @@ void NEGEMM::configure(const ITensor *a, const ITensor *b, const ITensor *c, ITe
if(run_optimised)
{
- _asm_glue.configure(a, b, d, alpha, beta, _reshape_b_only_on_first_run);
+ if(MEMInfo::get_policy() == MemoryPolicy::MINIMIZE)
+ {
+ _asm_glue.configure(a, b, d, alpha, beta, false);
+ }
+ else
+ {
+ _asm_glue.configure(a, b, d, alpha, beta, _reshape_b_only_on_first_run);
+ }
ARM_COMPUTE_ERROR_ON(!_asm_glue.is_configured());
}
else