changeset 30299:f306fe9bfa0d

Limit the size of the cache of latex parsed strings (bug #59546). * graphics.in.h (gh_manager::latex_data): New typedef moved from latex_renderer. (m_latex_cache, m_latex_keys): New data members. A map of cached latex_data and a list of keys. The latter allows for deleting the oldest entries when the cache becomes too large. (gh_manager::get_latex_data, gh_manager::set_latex_data): Cache accessor functions. * latex-text-renderer.cc: Remove global latex_cache variable. (latex_renderer::text_to_strlist,latex_renderer::render): Use the gh_manager to handle the cache.
author Pantxo Diribarne <pantxo.diribarne@gmail.com>
date Thu, 27 May 2021 22:49:26 +0200
parents 5797b9f87086
children 4ee01c14fccd
files libinterp/corefcn/graphics.in.h libinterp/corefcn/latex-text-renderer.cc
diffstat 2 files changed, 61 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/graphics.in.h	Thu Nov 18 17:45:49 2021 +0100
+++ b/libinterp/corefcn/graphics.in.h	Thu May 27 22:49:26 2021 +0200
@@ -38,6 +38,7 @@
 #include <set>
 #include <sstream>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "caseless-str.h"
@@ -6627,6 +6628,8 @@
 {
 public:
 
+  typedef std::pair<uint8NDArray /*pixels*/, std::string /*svg*/> latex_data;
+
   OCTINTERP_API gh_manager (octave::interpreter& interp);
 
   // FIXME: eventually eliminate these static functions and access
@@ -6797,6 +6800,35 @@
     return m_graphics_lock;
   }
 
+  latex_data get_latex_data (const std::string& key) const
+  {
+    latex_data retval;
+
+    const auto it = m_latex_cache.find (key);
+
+    if (it != m_latex_cache.end ())
+      retval = it->second;
+
+    return retval;
+  }
+
+  void set_latex_data (const std::string& key, latex_data val)
+  {
+    // Limit the number of cache entries to 500
+    if (m_latex_keys.size () >= 500)
+      {
+        auto it = m_latex_cache.find (m_latex_keys.front ());
+
+        if (it != m_latex_cache.end ())
+          m_latex_cache.erase (it);
+
+        m_latex_keys.pop_front ();
+      }
+
+    m_latex_cache[key] = val;
+    m_latex_keys.push_back (key);
+  }
+
 private:
 
   typedef std::map<graphics_handle, graphics_object>::iterator iterator;
@@ -6835,6 +6867,11 @@
 
   // A flag telling whether event processing must be constantly on.
   int m_event_processing;
+
+  // Cache of already parsed latex strings. Store a separate list of keys
+  // to allow for erasing oldest entries if cache size becomes too large.
+  std::unordered_map<std::string, latex_data> m_latex_cache;
+  std::list<std::string> m_latex_keys;
 };
 
 OCTINTERP_API void
--- a/libinterp/corefcn/latex-text-renderer.cc	Thu Nov 18 17:45:49 2021 +0100
+++ b/libinterp/corefcn/latex-text-renderer.cc	Thu May 27 22:49:26 2021 +0200
@@ -34,6 +34,7 @@
 #include "builtin-defun-decls.h"
 #include "dim-vector.h"
 #include "error.h"
+#include "graphics.h"
 #include "file-ops.h"
 #include "interpreter.h"
 #include "interpreter-private.h"
@@ -42,11 +43,6 @@
 
 namespace octave
 {
-  // FIXME: get rid of this global variable
-  // Store both the generated pixmap and the svg image
-  typedef std::pair<uint8NDArray /*pixels*/, std::string /*svg*/> latex_data;
-  std::unordered_map<std::string, latex_data> latex_cache;
-
   std::string
   quote_string (std::string str)
   {
@@ -113,7 +109,9 @@
     {
       Matrix bbox;
       uint8NDArray pixels;
+
       text_to_pixels (txt, pixels, bbox, 0, 0, rotation, interpreter, false);
+
       return bbox.extract_n (0, 2, 1, 2);
     }
 
@@ -129,7 +127,13 @@
       text_renderer::font fnt;
       text_renderer::string str ("", fnt, 0.0, 0.0);
       str.set_color (m_color);
-      str.set_svg_element (latex_cache[key (txt, halign)].second);
+
+      gh_manager& gh_mgr = octave::__get_gh_manager__ ("text_to_strlist");
+
+      gh_manager::latex_data ldata = gh_mgr.get_latex_data (key (txt, halign));
+
+      str.set_svg_element (ldata.second);
+
       lst.push_back (str);
     }
 
@@ -351,10 +355,12 @@
   latex_renderer::render (const std::string& txt, int halign)
   {
     // Render if it was not already done
-    auto it = latex_cache.find (key (txt, halign));
+    gh_manager& gh_mgr = octave::__get_gh_manager__ ("latex_renderer::render");
 
-    if (it != latex_cache.end ())
-      return it->second.first;
+    gh_manager::latex_data ldata = gh_mgr.get_latex_data (key (txt, halign));
+
+    if (! ldata.first.isempty ())
+      return ldata.first;
 
     uint8NDArray data;
 
@@ -450,11 +456,13 @@
       return data;
 
     // Cache pixel and svg data for this string
-    latex_cache[key (txt, halign)] = latex_data (data, svg_string);
+    ldata.first = data;
+    ldata.second = svg_string;
+
+    gh_mgr.set_latex_data (key (txt, halign), ldata);
 
     if (m_debug)
-      std::cout << "* Caching " << key (txt, halign)
-                << " (numel: " << latex_cache.size () << ")\n";
+      std::cout << "* Caching " << key (txt, halign) << std::endl;
 
     return data;
   }
@@ -468,7 +476,10 @@
   {
     // Return early for empty strings
     if (txt.empty ())
-      return;
+      {
+        bbox = Matrix (1, 4, 0.0);
+        return;
+      }
 
     if (ok ())
       pixels = render (txt, halign);