update to v1.8.8

This commit is contained in:
Daan Leijen 2025-01-03 17:56:15 -08:00
parent a0a6ad3cf9
commit 98699c983a
36 changed files with 694 additions and 433 deletions

View file

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.11.0"/>
<meta name="generator" content="Doxygen 1.13.1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>mi-malloc: Extended Functions</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
@ -54,7 +54,7 @@
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.11.0 -->
<!-- Generated by Doxygen 1.13.1 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
@ -196,13 +196,13 @@ Functions</h2></td></tr>
<tr class="memdesc:ga4c6486a1fdcd7a423b5f25fe4be8e0cf"><td class="mdescLeft">&#160;</td><td class="mdescRight">Manage a particular memory area for use by mimalloc. <br /></td></tr>
<tr class="separator:ga4c6486a1fdcd7a423b5f25fe4be8e0cf"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ga3132f521fb756fc0e8ec0b74fb58df50" id="r_ga3132f521fb756fc0e8ec0b74fb58df50"><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ga3132f521fb756fc0e8ec0b74fb58df50">mi_reserve_huge_os_pages_interleave</a> (size_t pages, size_t numa_nodes, size_t timeout_msecs)</td></tr>
<tr class="memdesc:ga3132f521fb756fc0e8ec0b74fb58df50"><td class="mdescLeft">&#160;</td><td class="mdescRight">Reserve <em>pages</em> of huge OS pages (1GiB) evenly divided over <em>numa_nodes</em> nodes, but stops after at most <code>timeout_msecs</code> seconds. <br /></td></tr>
<tr class="memdesc:ga3132f521fb756fc0e8ec0b74fb58df50"><td class="mdescLeft">&#160;</td><td class="mdescRight">Reserve <em class="arg">pages</em> of huge OS pages (1GiB) evenly divided over <em class="arg">numa_nodes</em> nodes, but stops after at most <code>timeout_msecs</code> seconds. <br /></td></tr>
<tr class="separator:ga3132f521fb756fc0e8ec0b74fb58df50"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ga7795a13d20087447281858d2c771cca1" id="r_ga7795a13d20087447281858d2c771cca1"><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ga7795a13d20087447281858d2c771cca1">mi_reserve_huge_os_pages_at</a> (size_t pages, int numa_node, size_t timeout_msecs)</td></tr>
<tr class="memdesc:ga7795a13d20087447281858d2c771cca1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Reserve <em>pages</em> of huge OS pages (1GiB) at a specific <em>numa_node</em>, but stops after at most <code>timeout_msecs</code> seconds. <br /></td></tr>
<tr class="memdesc:ga7795a13d20087447281858d2c771cca1"><td class="mdescLeft">&#160;</td><td class="mdescRight">Reserve <em class="arg">pages</em> of huge OS pages (1GiB) at a specific <em class="arg">numa_node</em>, but stops after at most <code>timeout_msecs</code> seconds. <br /></td></tr>
<tr class="separator:ga7795a13d20087447281858d2c771cca1"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:gaad25050b19f30cd79397b227e0157a3f" id="r_gaad25050b19f30cd79397b227e0157a3f"><td class="memItemLeft" align="right" valign="top">bool&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#gaad25050b19f30cd79397b227e0157a3f">mi_is_redirected</a> ()</td></tr>
<tr class="memdesc:gaad25050b19f30cd79397b227e0157a3f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Is the C runtime <em>malloc</em> API redirected? <br /></td></tr>
<tr class="memdesc:gaad25050b19f30cd79397b227e0157a3f"><td class="mdescLeft">&#160;</td><td class="mdescRight">Is the C runtime <em class="arg">malloc</em> API redirected? <br /></td></tr>
<tr class="separator:gaad25050b19f30cd79397b227e0157a3f"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:ga7d862c2affd5790381da14eb102a364d" id="r_ga7d862c2affd5790381da14eb102a364d"><td class="memItemLeft" align="right" valign="top">void&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="#ga7d862c2affd5790381da14eb102a364d">mi_process_info</a> (size_t *elapsed_msecs, size_t *user_msecs, size_t *system_msecs, size_t *current_rss, size_t *peak_rss, size_t *current_commit, size_t *peak_commit, size_t *page_faults)</td></tr>
<tr class="memdesc:ga7d862c2affd5790381da14eb102a364d"><td class="mdescLeft">&#160;</td><td class="mdescRight">Return process information (time and memory usage). <br /></td></tr>
@ -293,7 +293,7 @@ Functions</h2></td></tr>
<p>Type of deferred free functions. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">force</td><td>If <em>true</em> all outstanding items should be freed. </td></tr>
<tr><td class="paramname">force</td><td>If <em class="arg">true</em> all outstanding items should be freed. </td></tr>
<tr><td class="paramname">heartbeat</td><td>A monotonically increasing count. </td></tr>
<tr><td class="paramname">arg</td><td>Argument that was passed at registration to hold extra state.</td></tr>
</table>
@ -418,7 +418,7 @@ Functions</h2></td></tr>
<p>Eagerly free memory. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">force</td><td>If <em>true</em>, aggressively return memory to the OS (can be expensive!)</td></tr>
<tr><td class="paramname">force</td><td>If <em class="arg">true</em>, aggressively return memory to the OS (can be expensive!)</td></tr>
</table>
</dd>
</dl>
@ -518,13 +518,13 @@ Functions</h2></td></tr>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">heap_tag</td><td>The heap tag associated with this heap; heaps only reclaim memory between heaps with the same tag. </td></tr>
<tr><td class="paramname">allow_destroy</td><td>Is <em>mi_heap_destroy</em> allowed? Not allowing this allows the heap to reclaim memory from terminated threads. </td></tr>
<tr><td class="paramname">allow_destroy</td><td>Is <em class="arg">mi_heap_destroy</em> allowed? Not allowing this allows the heap to reclaim memory from terminated threads. </td></tr>
<tr><td class="paramname">arena_id</td><td>If not 0, the heap will only allocate from the specified arena. </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>A new heap or <code>NULL</code> on failure.</dd></dl>
<p>The <em>arena_id</em> can be used by runtimes to allocate only in a specified pre-reserved arena. This is used for example for a compressed pointer heap in Koka. The <em>heap_tag</em> enables heaps to keep objects of a certain type isolated to heaps with that tag. This is used for example in the CPython integration. </p>
<p>The <em class="arg">arena_id</em> can be used by runtimes to allocate only in a specified pre-reserved arena. This is used for example for a compressed pointer heap in Koka. The <em class="arg">heap_tag</em> enables heaps to keep objects of a certain type isolated to heaps with that tag. This is used for example in the CPython integration. </p>
</div>
</div>
@ -576,7 +576,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd><em>true</em> if this is a pointer into our heap. This function is relatively fast. </dd></dl>
<dl class="section return"><dt>Returns</dt><dd><em class="arg">true</em> if this is a pointer into our heap. This function is relatively fast. </dd></dl>
</div>
</div>
@ -595,8 +595,8 @@ Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Is the C runtime <em>malloc</em> API redirected? </p>
<dl class="section return"><dt>Returns</dt><dd><em>true</em> if all malloc API calls are redirected to mimalloc.</dd></dl>
<p>Is the C runtime <em class="arg">malloc</em> API redirected? </p>
<dl class="section return"><dt>Returns</dt><dd><em class="arg">true</em> if all malloc API calls are redirected to mimalloc.</dd></dl>
<p>Currently only used on Windows. </p>
</div>
@ -623,7 +623,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>a pointer to newly allocated memory of at least <em>size</em> bytes, or <em>NULL</em> if out of memory. This function is meant for use in run-time systems for best performance and does not check if <em>size</em> was indeed small &ndash; use with care! </dd></dl>
<dl class="section return"><dt>Returns</dt><dd>a pointer to newly allocated memory of at least <em class="arg">size</em> bytes, or <em class="arg">NULL</em> if out of memory. This function is meant for use in run-time systems for best performance and does not check if <em class="arg">size</em> was indeed small &ndash; use with care! </dd></dl>
</div>
</div>
@ -672,13 +672,13 @@ Functions</h2></td></tr>
<tr><td class="paramname">start</td><td>Start of the memory area </td></tr>
<tr><td class="paramname">size</td><td>The size of the memory area. </td></tr>
<tr><td class="paramname">is_committed</td><td>Is the area already committed? </td></tr>
<tr><td class="paramname">is_large</td><td>Does it consist of large OS pages? Set this to <em>true</em> as well for memory that should not be decommitted or protected (like rdma etc.) </td></tr>
<tr><td class="paramname">is_large</td><td>Does it consist of large OS pages? Set this to <em class="arg">true</em> as well for memory that should not be decommitted or protected (like rdma etc.) </td></tr>
<tr><td class="paramname">is_zero</td><td>Does the area consists of zero's? </td></tr>
<tr><td class="paramname">numa_node</td><td>Possible associated numa node or <code>-1</code>. </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd><em>true</em> if successful, and <em>false</em> on error. </dd></dl>
<dl class="section return"><dt>Returns</dt><dd><em class="arg">true</em> if successful, and <em class="arg">false</em> on error. </dd></dl>
</div>
</div>
@ -812,7 +812,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<p>The <em>current_rss</em> is precise on Windows and MacOSX; other systems estimate this using <em>current_commit</em>. The <em>commit</em> is precise on Windows but estimated on other systems as the amount of read/write accessible memory reserved by mimalloc. </p>
<p>The <em class="arg">current_rss</em> is precise on Windows and MacOSX; other systems estimate this using <em class="arg">current_commit</em>. The <em class="arg">commit</em> is precise on Windows but estimated on other systems as the amount of read/write accessible memory reserved by mimalloc. </p>
</div>
</div>
@ -838,12 +838,12 @@ Functions</h2></td></tr>
<p>Register a deferred free function. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">deferred_free</td><td>Address of a deferred free-ing function or <em>NULL</em> to unregister. </td></tr>
<tr><td class="paramname">deferred_free</td><td>Address of a deferred free-ing function or <em class="arg">NULL</em> to unregister. </td></tr>
<tr><td class="paramname">arg</td><td>Argument that will be passed on to the deferred free function.</td></tr>
</table>
</dd>
</dl>
<p>Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the <em>force</em> parameter is <em>true</em> all possible memory should be freed. The per-thread <em>heartbeat</em> parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The <em>deferred_free</em> function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one <em>deferred_free</em> function can be active. </p>
<p>Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the <em class="arg">force</em> parameter is <em class="arg">true</em> all possible memory should be freed. The per-thread <em class="arg">heartbeat</em> parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The <em class="arg">deferred_free</em> function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one <em class="arg">deferred_free</em> function can be active. </p>
</div>
</div>
@ -869,17 +869,17 @@ Functions</h2></td></tr>
<p>Register an error callback function. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">errfun</td><td>The error function that is called on an error (use <em>NULL</em> for default) </td></tr>
<tr><td class="paramname">errfun</td><td>The error function that is called on an error (use <em class="arg">NULL</em> for default) </td></tr>
<tr><td class="paramname">arg</td><td>Extra argument that will be passed on to the error function.</td></tr>
</table>
</dd>
</dl>
<p>The <em>errfun</em> function is called on an error in mimalloc after emitting an error message (through the output function). It as always legal to just return from the <em>errfun</em> function in which case allocation functions generally return <em>NULL</em> or ignore the condition. The default function only calls abort() when compiled in secure mode with an <em>EFAULT</em> error. The possible error codes are:</p><ul>
<li><em>EAGAIN:</em> Double free was detected (only in debug and secure mode).</li>
<li><em>EFAULT:</em> Corrupted free list or meta-data was detected (only in debug and secure mode).</li>
<li><em>ENOMEM:</em> Not enough memory available to satisfy the request.</li>
<li><em>EOVERFLOW:</em> Too large a request, for example in <a class="el" href="group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56" title="Allocate zero-initialized count elements of size bytes.">mi_calloc()</a>, the <em>count</em> and <em>size</em> parameters are too large.</li>
<li><em>EINVAL:</em> Trying to free or re-allocate an invalid pointer. </li>
<p>The <em class="arg">errfun</em> function is called on an error in mimalloc after emitting an error message (through the output function). It as always legal to just return from the <em class="arg">errfun</em> function in which case allocation functions generally return <em class="arg">NULL</em> or ignore the condition. The default function only calls abort() when compiled in secure mode with an <em class="arg">EFAULT</em> error. The possible error codes are:</p><ul>
<li><em class="arg">EAGAIN:</em> Double free was detected (only in debug and secure mode).</li>
<li><em class="arg">EFAULT:</em> Corrupted free list or meta-data was detected (only in debug and secure mode).</li>
<li><em class="arg">ENOMEM:</em> Not enough memory available to satisfy the request.</li>
<li><em class="arg">EOVERFLOW:</em> Too large a request, for example in <a class="el" href="group__malloc.html#ga6686568014b54d1e6c7ac64a076e4f56" title="Allocate zero-initialized count elements of size bytes.">mi_calloc()</a>, the <em class="arg">count</em> and <em class="arg">size</em> parameters are too large.</li>
<li><em class="arg">EINVAL:</em> Trying to free or re-allocate an invalid pointer. </li>
</ul>
</div>
@ -939,7 +939,7 @@ Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Reserve <em>pages</em> of huge OS pages (1GiB) at a specific <em>numa_node</em>, but stops after at most <code>timeout_msecs</code> seconds. </p>
<p>Reserve <em class="arg">pages</em> of huge OS pages (1GiB) at a specific <em class="arg">numa_node</em>, but stops after at most <code>timeout_msecs</code> seconds. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">pages</td><td>The number of 1GiB pages to reserve. </td></tr>
@ -948,8 +948,8 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, <em>ENOMEM</em> if running out of memory, or <em>ETIMEDOUT</em> if timed out.</dd></dl>
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em>timeout_msecs</em> are expired if it estimates it will take more than 1.5 times <em>timeout_msecs</em>. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented. </p>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, <em class="arg">ENOMEM</em> if running out of memory, or <em class="arg">ETIMEDOUT</em> if timed out.</dd></dl>
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em class="arg">timeout_msecs</em> are expired if it estimates it will take more than 1.5 times <em class="arg">timeout_msecs</em>. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented. </p>
</div>
</div>
@ -998,7 +998,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, <em>ENOMEM</em> if running out of memory, or <em>ETIMEDOUT</em> if timed out. </dd></dl>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, <em class="arg">ENOMEM</em> if running out of memory, or <em class="arg">ETIMEDOUT</em> if timed out. </dd></dl>
</div>
</div>
@ -1026,7 +1026,7 @@ Functions</h2></td></tr>
</table>
</div><div class="memdoc">
<p>Reserve <em>pages</em> of huge OS pages (1GiB) evenly divided over <em>numa_nodes</em> nodes, but stops after at most <code>timeout_msecs</code> seconds. </p>
<p>Reserve <em class="arg">pages</em> of huge OS pages (1GiB) evenly divided over <em class="arg">numa_nodes</em> nodes, but stops after at most <code>timeout_msecs</code> seconds. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">pages</td><td>The number of 1GiB pages to reserve. </td></tr>
@ -1035,8 +1035,8 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, <em>ENOMEM</em> if running out of memory, or <em>ETIMEDOUT</em> if timed out.</dd></dl>
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em>timeout_msecs</em> are expired if it estimates it will take more than 1.5 times <em>timeout_msecs</em>. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented. </p>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, <em class="arg">ENOMEM</em> if running out of memory, or <em class="arg">ETIMEDOUT</em> if timed out.</dd></dl>
<p>The reserved memory is used by mimalloc to satisfy allocations. May quit before <em class="arg">timeout_msecs</em> are expired if it estimates it will take more than 1.5 times <em class="arg">timeout_msecs</em>. The time limit is needed because on some operating systems it can take a long time to reserve contiguous memory if the physical memory is fragmented. </p>
</div>
</div>
@ -1073,7 +1073,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd><em>0</em> if successful, and an error code otherwise (e.g. <code>ENOMEM</code>). </dd></dl>
<dl class="section return"><dt>Returns</dt><dd><em class="arg">0</em> if successful, and an error code otherwise (e.g. <code>ENOMEM</code>). </dd></dl>
</div>
</div>
@ -1193,8 +1193,8 @@ Functions</h2></td></tr>
<p>Print the main statistics. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">out</td><td>An output function or <em>NULL</em> for the default. </td></tr>
<tr><td class="paramname">arg</td><td>Optional argument passed to <em>out</em> (if not <em>NULL</em>)</td></tr>
<tr><td class="paramname">out</td><td>An output function or <em class="arg">NULL</em> for the default. </td></tr>
<tr><td class="paramname">arg</td><td>Optional argument passed to <em class="arg">out</em> (if not <em class="arg">NULL</em>)</td></tr>
</table>
</dd>
</dl>
@ -1367,8 +1367,8 @@ Functions</h2></td></tr>
<p>Print out heap statistics for this thread. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">out</td><td>An output function or <em>NULL</em> for the default. </td></tr>
<tr><td class="paramname">arg</td><td>Optional argument passed to <em>out</em> (if not <em>NULL</em>)</td></tr>
<tr><td class="paramname">out</td><td>An output function or <em class="arg">NULL</em> for the default. </td></tr>
<tr><td class="paramname">arg</td><td>Optional argument passed to <em class="arg">out</em> (if not <em class="arg">NULL</em>)</td></tr>
</table>
</dd>
</dl>
@ -1394,12 +1394,12 @@ Functions</h2></td></tr>
<p>Return the available bytes in a memory block. </p>
<dl class="params"><dt>Parameters</dt><dd>
<table class="params">
<tr><td class="paramname">p</td><td>Pointer to previously allocated memory (or <em>NULL</em>) </td></tr>
<tr><td class="paramname">p</td><td>Pointer to previously allocated memory (or <em class="arg">NULL</em>) </td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>Returns the available bytes in the memory block, or 0 if <em>p</em> was <em>NULL</em>.</dd></dl>
<p>The returned size can be used to call <em>mi_expand</em> successfully. The returned size is always at least equal to the allocated size of <em>p</em>.</p>
<dl class="section return"><dt>Returns</dt><dd>Returns the available bytes in the memory block, or 0 if <em class="arg">p</em> was <em class="arg">NULL</em>.</dd></dl>
<p>The returned size can be used to call <em class="arg">mi_expand</em> successfully. The returned size is always at least equal to the allocated size of <em class="arg">p</em>.</p>
<dl class="section see"><dt>See also</dt><dd><a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/msize?view=vs-2017">_msize</a> (Windows) </dd>
<dd>
<a href="http://man7.org/linux/man-pages/man3/malloc_usable_size.3.html">malloc_usable_size</a> (Linux) </dd>
@ -1430,7 +1430,7 @@ Functions</h2></td></tr>
</table>
</dd>
</dl>
<dl class="section return"><dt>Returns</dt><dd>a pointer to newly allocated zero-initialized memory of at least <em>size</em> bytes, or <em>NULL</em> if out of memory. This function is meant for use in run-time systems for best performance and does not check if <em>size</em> was indeed small &ndash; use with care! </dd></dl>
<dl class="section return"><dt>Returns</dt><dd>a pointer to newly allocated zero-initialized memory of at least <em class="arg">size</em> bytes, or <em class="arg">NULL</em> if out of memory. This function is meant for use in run-time systems for best performance and does not check if <em class="arg">size</em> was indeed small &ndash; use with care! </dd></dl>
</div>
</div>
@ -1439,7 +1439,7 @@ Functions</h2></td></tr>
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.11.0 </li>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.13.1 </li>
</ul>
</div>
</body>