mCRL2
Loading...
Searching...
No Matches
function_symbol_pool.cpp
Go to the documentation of this file.
1// Author(s): Maurice Laveaux
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
9
11
13
14#include <chrono>
15
16using namespace atermpp;
17using namespace atermpp::detail;
18using namespace mcrl2::utilities;
19using namespace mcrl2::utilities::detail;
20
22{
23 // Initialize the default function symbols.
24 m_as_int = create("<aterm_int>", 0);
25 m_as_list = create("<list_constructor>", 2);
26 m_as_empty_list = create("<empty_list>", 0);
27
28 // Initialize the global copies of these default function symbols.
32}
33
34void function_symbol_pool::create_helper(const std::string& name)
35{
36 if constexpr (GlobalThreadSafe) { m_mutex.lock(); }
37
38 // Check whether there is a registered prefix p such that name equal pn where n is a number.
39 // In that case prevent that pn will be generated as a fresh function name.
40 std::size_t start_of_index = name.find_last_not_of("0123456789") + 1;
41
42 if (start_of_index < name.size()) // Otherwise there is no trailing number.
43 {
44 std::string potential_number = name.substr(start_of_index); // Get the trailing string after prefix_ of function_name.
45 std::string prefix = name.substr(0, start_of_index);
46 auto prefix_it = m_prefix_to_register_function_map.find(prefix);
47 if (prefix_it != m_prefix_to_register_function_map.end()) // points to the prefix.
48 {
49 try
50 {
51 std::size_t number = std::stoul(potential_number);
52 *prefix_it->second = std::max(*prefix_it->second, number + 1); // Set the index belonging to the found prefix to at least a safe number+1.
53 }
54 catch (std::exception&)
55 {
56 // Can be std::invalid_argument or an out_of_range exception.
57 // In both cases nothing needs to be done, and the exception can be ignored.
58 }
59 }
60 }
61
62 if constexpr (GlobalThreadSafe) { m_mutex.unlock(); }
63}
64
65function_symbol function_symbol_pool::create(std::string&& name, const std::size_t arity, const bool check_for_registered_functions)
66{
67 auto it = m_symbol_set.find(name, arity);
68 if (it != m_symbol_set.end())
69 {
71
72 // The element already exists so return it.
74 }
75 else
76 {
78
79 const _function_symbol& symbol = *m_symbol_set.emplace(std::forward<std::string>(name), arity).first;
80 if (check_for_registered_functions)
81 {
82 create_helper(symbol.name());
83 }
84
86 }
87}
88
89function_symbol function_symbol_pool::create(const std::string& name, const std::size_t arity, const bool check_for_registered_functions)
90{
91 auto it = m_symbol_set.find(name, arity);
92 if (it != m_symbol_set.end())
93 {
95
96 // The element already exists so return it.
98 }
99 else
100 {
102
103 const _function_symbol& symbol = *m_symbol_set.emplace(name, arity).first;
104 if (check_for_registered_functions)
105 {
106 create_helper(name);
107 }
108
109 return function_symbol(_function_symbol::ref(&symbol));
110 }
111}
112
113void function_symbol_pool::deregister(const std::string& prefix)
114{
115 m_mutex.lock();
117 m_mutex.unlock();
118}
119
120std::shared_ptr<std::size_t> function_symbol_pool::register_prefix(const std::string& prefix)
121{
122 m_mutex.lock();
123
124 auto it = m_prefix_to_register_function_map.find(prefix);
125 if (it != m_prefix_to_register_function_map.end())
126 {
127 auto result = it->second;
128 m_mutex.unlock();
129 return result;
130 }
131 else
132 {
133 std::size_t index = get_sufficiently_large_postfix_index(prefix);
134 std::shared_ptr<std::size_t> shared_index = std::make_shared<std::size_t>(index);
135 m_prefix_to_register_function_map[prefix] = shared_index;
136
137 m_mutex.unlock();
138 return shared_index;
139 }
140}
141
142std::size_t function_symbol_pool::get_sufficiently_large_postfix_index(const std::string& prefix) const
143{
144 std::size_t index = 0;
145 for (const auto& f : m_symbol_set)
146 {
147 const std::string& function_name = f.name();
148
149 if (function_name.compare(0, prefix.size(), prefix) == 0) // The function name starts with the prefix
150 {
151 std::string potential_number = function_name.substr(prefix.size()); // Get the trailing string after prefix_ of function_name.
152 std::size_t end_of_number;
153 try
154 {
155 std::size_t number = std::stoul(potential_number, &end_of_number);
156 if (end_of_number == potential_number.size()) // A proper number was read.
157 {
158 if (number >= index)
159 {
160 index = number + 1;
161 }
162 }
163 }
164 catch (std::exception&)
165 {
166 // Can be std::invalid_argument or an out_of_range exception.
167 // In both cases nothing needs to be done, and the exception can be ignored.
168 }
169 }
170 }
171
172 return index;
173}
174
176{
177 // Prevents changes to the symbol_set
178 std::unique_lock lock(m_mutex);
179
180 auto timestamp = std::chrono::system_clock::now();
181 std::size_t old_size = size();
182
183 // Clean up function symbols with a zero reference count.
184 for (auto it = m_symbol_set.begin(); it != m_symbol_set.end(); )
185 {
186 if (it->reference_count() == 0)
187 {
188 it = m_symbol_set.erase(it);
189 }
190 else
191 {
192 ++it;
193 }
194 }
195
196 std::size_t erased_blocks = 0; //m_symbol_set.get_allocator().consolidate();
197
198 if constexpr (EnableGarbageCollectionMetrics)
199 {
200 auto sweep_duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - timestamp).count();
201
202 // Print the relevant information.
203 mCRL2log(mcrl2::log::info) << "function_symbol_pool: Garbage collected " << old_size - size() << " function symbols, " << size() << " function symbols remaining in "
204 << sweep_duration << " ms.\n";
205
206 mCRL2log(mcrl2::log::info) << "function_symbol_pool: Consolidate removed " << erased_blocks << " blocks.\n";
207 }
208
209 if constexpr (EnableHashtableMetrics)
210 {
212 }
213
214 if constexpr (EnableCreationMetrics)
215 {
216 mCRL2log(mcrl2::log::info) << "g_function_symbol_pool: Stores " << size() << " function symbols. create() " << m_function_symbol_metrics.message() << ".\n";
217 }
218
219 if constexpr (EnableReferenceCountMetrics)
220 {
221 mCRL2log(mcrl2::log::info) << "g_function_symbol_pool: all reference counts changed " << _function_symbol::reference_count_changes() << " times.\n";
222 }
223}
225{
227}
size_type size() const
Returns the number of arguments of this term.
Definition aterm.h:151
Stores the data for a function symbol (name, arity) pair.
const std::string & name() const noexcept
void sweep()
Collect all garbage function symbols.
std::map< std::string, std::shared_ptr< std::size_t > > m_prefix_to_register_function_map
A map that records a function for each prefix that must be called to set the postfix number to a suff...
void deregister(const std::string &prefix)
Restore the index back to index before registering this prefix. \threadsafe.
std::shared_ptr< std::size_t > register_prefix(const std::string &prefix)
void resize_if_needed()
Resize the function symbol pool if necessary.
unordered_set m_symbol_set
Stores the underlying function symbols.
void create_helper(const std::string &name)
std::size_t get_sufficiently_large_postfix_index(const std::string &prefix) const
Get an index such that no function symbol with name prefix + returned value and any value above it al...
mcrl2::utilities::cache_metric m_function_symbol_metrics
Track the number of function symbols found in or added to the set.
function_symbol create(const std::string &name, const std::size_t arity, const bool check_for_registered_functions=false)
Creates a function symbol pair (name, arity), returns a pointer to an existing element if this pair i...
void miss()
Should be called when searching the cache was a miss.
void hit()
Should be called when searching the cache was a hit.
static std::atomic< std::size_t > & reference_count_changes()
Obtain the number of times that this reference count has changed.
void erase(const Args &... args)
Erases the given key_type(args...) from the unordered set.
std::pair< iterator, bool > emplace(Args &&... args)
Inserts an element Key(args...) into the set if it did not already exist.
void rehash_if_needed()
Resizes the hash table if necessary.
const_iterator find(const Args &... args) const
Searches whether an object key_type(args...) occurs in the set.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
static constexpr bool EnableHashtableMetrics
Enable to print hashtable collision, size and number of buckets.
static constexpr bool EnableCreationMetrics
Enable to obtain the percentage of terms found compared to allocated.
function_symbol g_as_empty_list
function_symbol g_as_list
static constexpr bool EnableGarbageCollectionMetrics
Enable to print garbage collection statistics.
function_symbol g_as_int
These function symbols are used to indicate integer, list and empty list terms.
The main namespace for the aterm++ library.
Definition algorithm.h:21
static constexpr bool GlobalThreadSafe
Enables thread safety for the whole toolset.
static constexpr bool EnableReferenceCountMetrics
Enable to count the number of reference count changes.
void print_performance_statistics(const T &unordered_set)
Prints various information for unordered_set like data structures.
add your file description here.