mimalloc-pprof 1.0.0

mimalloc global allocator with pprof-compatible sampled heap profiling
Documentation
/* ABI layout probe for the Rust mirrors in src/sys.rs (issue: C/Rust API parity).

   Every `#[repr(C)]` struct in `src/sys.rs` is a hand-written mirror of a C struct, and
   every `mi_option_*` constant there is a hand-written mirror of an enumerator whose
   value is positional. Both are silent-corruption hazards: a mirror that drifts writes
   the wrong field, or sets the wrong option, with no diagnostic anywhere.

   So the C side publishes what it actually laid out. This file exports a name/value
   table -- `sizeof:<type>`, `offset:<type>.<field>`, `option:<enumerator>`, and the
   versioned/sentinel constants -- which `tests/t19_layout.rs` looks up BY NAME and
   compares against `core::mem::size_of` / `core::mem::offset_of!` and the Rust
   constants. Lookup by name (rather than by index) is deliberate: a field renamed or
   dropped on either side fails as "missing key", never as a coincidentally-equal number.

   This file lives under rust/ on purpose: it is a binding-verification artifact, not
   part of the C library, so it never enters the CMake build or the amalgamation. It is
   compiled into the crate's static library but referenced only from the test, so the
   linker drops it from ordinary consumers.

   Nothing here is gated on MI_PPROF: the profiler's public *types* are declared
   unconditionally in include/mimalloc/profile.h (only the implementation is gated), so
   the layout the mirrors must match is the same in both feature modes. */

#include <stddef.h>

#include "mimalloc-pprof-amalgamated.h"
#include "mimalloc-stats.h"

/* ---------------------------------------------------------------------------------------
   #322: SIGNATURES, not just layouts.

   The layout table below proves every `#[repr(C)]` mirror in src/sys.rs agrees with the C
   compiler about sizes and offsets, and ci/check_rust_surface.py proves every fork export
   exists in sys.rs and is called from lib.rs. Neither looks at a function's SIGNATURE:
   sys.rs declares each prototype by hand, the crate links against a bare symbol name, and
   the Rust declaration is simply believed. A parameter added, a `size_t` widened, a `bool`
   become `int`, two arguments swapped -- nothing here would have noticed, and on most ABIs
   the result is silent argument corruption. That is exactly the failure class the layout
   probe was added to eliminate for structs, and this fork re-pins its overlay to newer
   upstream/dev3 commits, which is the door such a change arrives through.

   So each line below is the signature src/sys.rs assumes, spelled in C, AFTER the real
   headers are included above. If a real prototype disagrees, this file stops the build
   with a redeclaration conflict that names the offending function -- rather than passing
   arguments through a wrong ABI at run time. Nothing calls these; they exist to be
   compared by the compiler.

   Generated from the `unsafe extern "C"` block in src/sys.rs; keep them in step when that
   block changes (a declaration removed here is a gap, not a fix). */

void* mi_malloc(size_t size);
void* mi_zalloc(size_t size);
void* mi_calloc(size_t count, size_t size);
void* mi_realloc(void* p, size_t newsize);
void mi_free(void* p);
void* mi_malloc_aligned(size_t size, size_t alignment);
void* mi_zalloc_aligned(size_t size, size_t alignment);
void* mi_realloc_aligned(void* p, size_t newsize, size_t alignment);
void* mi_rezalloc(void* p, size_t newsize);
void* mi_recalloc(void* p, size_t newcount, size_t size);
void* mi_rezalloc_aligned(void* p, size_t newsize, size_t alignment);
void* mi_recalloc_aligned(void* p, size_t newcount, size_t size, size_t alignment);
void* mi_expand(void* p, size_t newsize);
size_t mi_usable_size(const void* p);
bool mi_dhat_start(void);
void mi_dhat_stop(void);
bool mi_dhat_is_enabled(void);
bool mi_dhat_stats_get(mi_dhat_stats_t* stats);
bool mi_dhat_dump(const char* path);
bool mi_prof_start(size_t sample_rate);
bool mi_prof_start_seeded(size_t sample_rate, uint64_t seed);
bool mi_prof_start_ex(const mi_prof_config_t* config);
void mi_prof_stop(void);
bool mi_prof_is_enabled(void);
bool mi_prof_dump(const char* path);
bool mi_prof_dump_writer(mi_prof_write_fun* write, void* arg);
bool mi_prof_dump_proto(const char* path);
bool mi_prof_dump_proto_writer(mi_prof_write_fun* write, void* arg);
void mi_prof_reset(void);
void mi_prof_debug_stats(size_t* records, size_t* bytes, size_t* unique_stacks);
bool mi_prof_stats_get(mi_prof_stats_t* stats);
bool mi_prof_visit(mi_prof_visit_fun* visitor, void* arg);
mi_prof_snapshot_t* mi_prof_snapshot_new(void);
bool mi_prof_snapshot_visit(const mi_prof_snapshot_t* snap, mi_prof_visit_fun* visitor, void* arg);
void mi_prof_snapshot_free(mi_prof_snapshot_t* snap);
bool mi_prof_modules_visit(mi_prof_module_visit_fun* visitor, void* arg);
void* mi_unwrapped_malloc(size_t size, size_t alignment);
void mi_unwrapped_free(void* p);
void* mi_unwrapped_realloc(void* p, size_t new_size, size_t alignment);
char* mi_heap_dump_json(bool include_blocks, bool hash_addresses);
char* mi_heap_dump_json_ex(bool include_blocks, bool hash_addresses, size_t wait_ms);
size_t mi_heap_get_seq(mi_heap_t* heap);
int mi_heap_snapshot(int fd, unsigned int flags);
int mi_heap_snapshot_to_file(const char* path, unsigned int flags);
void mi_on_thread_idle(void);
bool mi_on_thread_idle_start(void);
void mi_on_thread_idle_end(void);
void mi_scavenger_stop(void);
void mi_purge_holes_stats_get(mi_purge_holes_stats_t* stats);
void mi_purge_holes_report(void);
int mi_purge_all_ex(mi_purge_flags_t flags, size_t wait_ms, mi_purge_all_report_t* report);
void mi_purge_all(bool force);
bool mi_option_is_enabled(mi_option_t option);
void mi_option_enable(mi_option_t option);
void mi_option_disable(mi_option_t option);
void mi_option_set_enabled(mi_option_t option, bool enable);
void mi_option_set_enabled_default(mi_option_t option, bool enable);
long mi_option_get(mi_option_t option);
long mi_option_get_clamp(mi_option_t option, long min, long max);
size_t mi_option_get_size(mi_option_t option);
void mi_option_set(mi_option_t option, long value);
void mi_option_set_default(mi_option_t option, long value);
void mi_options_print_out(mi_output_fun* out, void* arg);
bool mi_stats_get(mi_stats_t* stats);
char* mi_stats_get_json(size_t buf_size, char* buf);
char* mi_stats_as_json(mi_stats_t* stats, size_t buf_size, char* buf);
void mi_stats_print_out(mi_output_fun* out, void* arg);
size_t mi_stats_get_bin_size(size_t bin);
bool mi_heap_stats_get(mi_heap_t* heap, mi_stats_t* stats);
char* mi_heap_stats_get_json(mi_heap_t* heap, size_t buf_size, char* buf);
void mi_heap_stats_print_out(mi_heap_t* heap, mi_output_fun* out, void* arg);
void mi_heap_stats_merge_to_subproc(mi_heap_t* heap);
bool mi_subproc_stats_get(mi_subproc_id_t subproc_id, mi_stats_t* stats);
bool mi_subproc_stats_get_exclusive(mi_subproc_id_t subproc_id, mi_stats_t* stats);
char* mi_subproc_stats_get_json(mi_subproc_id_t subproc_id, size_t buf_size, char* buf);
void mi_subproc_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun* out, void* arg);
void mi_subproc_heap_stats_print_out(mi_subproc_id_t subproc_id, mi_output_fun* out, void* arg);
mi_subproc_id_t mi_subproc_main(void);
mi_subproc_id_t mi_subproc_current(void);
bool mi_memory_tracking_set_enabled(bool enabled);
bool mi_memory_tracking_is_enabled(void);
bool mi_memory_snapshot(mi_memory_snapshot_t* out);
bool mi_memory_set_callbacks(const mi_memory_callbacks_t* callbacks);
bool mi_memory_visit_live_allocations(mi_memory_allocation_visit_fun* visitor, void* arg);

typedef struct mi_rs_layout_entry_s {
  const char* name;
  size_t      value;
} mi_rs_layout_entry_t;

#define MI_RS_SIZEOF(T)      { "sizeof:" #T, sizeof(T) },
#define MI_RS_OFFSET(T, F)   { "offset:" #T "." #F, offsetof(T, F) },
#define MI_RS_CONST(N)       { "const:" #N, (size_t)(N) },
#define MI_RS_OPTION(N)      { "option:" #N, (size_t)(N) },

static const mi_rs_layout_entry_t mi_rs_layout_entries[] = {
  /* ---- include/mimalloc/profile.h ---- */
  MI_RS_SIZEOF(mi_prof_stats_t)
  MI_RS_OFFSET(mi_prof_stats_t, size)
  MI_RS_OFFSET(mi_prof_stats_t, version)
  MI_RS_OFFSET(mi_prof_stats_t, enabled)
  MI_RS_OFFSET(mi_prof_stats_t, accum)
  MI_RS_OFFSET(mi_prof_stats_t, sample_rate)
  MI_RS_OFFSET(mi_prof_stats_t, live_samples)
  MI_RS_OFFSET(mi_prof_stats_t, live_bytes)
  MI_RS_OFFSET(mi_prof_stats_t, accum_samples)
  MI_RS_OFFSET(mi_prof_stats_t, accum_bytes)
  MI_RS_OFFSET(mi_prof_stats_t, unique_stacks)
  MI_RS_OFFSET(mi_prof_stats_t, arena_committed)
  MI_RS_OFFSET(mi_prof_stats_t, stack_table_overflows)
  MI_RS_OFFSET(mi_prof_stats_t, dropped_samples)
  MI_RS_OFFSET(mi_prof_stats_t, heap_committed)
  MI_RS_OFFSET(mi_prof_stats_t, heap_reserved)
  MI_RS_OFFSET(mi_prof_stats_t, heap_malloc_requested)
  MI_RS_OFFSET(mi_prof_stats_t, heap_pages)
  MI_RS_OFFSET(mi_prof_stats_t, heap_pages_abandoned)
  MI_RS_OFFSET(mi_prof_stats_t, heap_count)
  MI_RS_OFFSET(mi_prof_stats_t, theap_count)
  MI_RS_OFFSET(mi_prof_stats_t, heap_purged)
  MI_RS_OFFSET(mi_prof_stats_t, heap_stats_detailed)

  MI_RS_SIZEOF(mi_prof_config_t)
  MI_RS_OFFSET(mi_prof_config_t, size)
  MI_RS_OFFSET(mi_prof_config_t, version)
  MI_RS_OFFSET(mi_prof_config_t, mode)
  MI_RS_OFFSET(mi_prof_config_t, sample_interval)
  MI_RS_OFFSET(mi_prof_config_t, max_profiler_bytes)
  MI_RS_OFFSET(mi_prof_config_t, seed)
  MI_RS_OFFSET(mi_prof_config_t, accum)
  MI_RS_OFFSET(mi_prof_config_t, max_stack_depth)
  MI_RS_OFFSET(mi_prof_config_t, dump_at_exit)
  MI_RS_OFFSET(mi_prof_config_t, dump_format)

  MI_RS_SIZEOF(mi_prof_sample_info_t)
  MI_RS_OFFSET(mi_prof_sample_info_t, stack)
  MI_RS_OFFSET(mi_prof_sample_info_t, depth)
  MI_RS_OFFSET(mi_prof_sample_info_t, live_objects)
  MI_RS_OFFSET(mi_prof_sample_info_t, live_bytes)
  MI_RS_OFFSET(mi_prof_sample_info_t, accum_objects)
  MI_RS_OFFSET(mi_prof_sample_info_t, accum_bytes)

  MI_RS_SIZEOF(mi_prof_module_info_t)
  MI_RS_OFFSET(mi_prof_module_info_t, path)
  MI_RS_OFFSET(mi_prof_module_info_t, base)
  MI_RS_OFFSET(mi_prof_module_info_t, size)

  MI_RS_CONST(MI_PROF_STAT_VERSION)
  MI_RS_CONST(MI_PROF_CONFIG_VERSION)
  MI_RS_CONST(MI_PROF_FORMAT_TEXT)
  MI_RS_CONST(MI_PROF_FORMAT_PROTO)
  MI_RS_CONST(MI_PROF_CONFIG_FALLBACK)
  MI_RS_CONST(MI_PROF_CONFIG_OVERRIDE)

  /* ---- include/mimalloc/dhat.h ---- */
  MI_RS_SIZEOF(mi_dhat_stats_t)
  MI_RS_OFFSET(mi_dhat_stats_t, size)
  MI_RS_OFFSET(mi_dhat_stats_t, version)
  MI_RS_OFFSET(mi_dhat_stats_t, enabled)
  MI_RS_OFFSET(mi_dhat_stats_t, incomplete)
  MI_RS_OFFSET(mi_dhat_stats_t, total_bytes)
  MI_RS_OFFSET(mi_dhat_stats_t, total_blocks)
  MI_RS_OFFSET(mi_dhat_stats_t, live_bytes)
  MI_RS_OFFSET(mi_dhat_stats_t, live_blocks)
  MI_RS_OFFSET(mi_dhat_stats_t, peak_bytes)
  MI_RS_OFFSET(mi_dhat_stats_t, peak_blocks)
  MI_RS_OFFSET(mi_dhat_stats_t, dropped)
  MI_RS_OFFSET(mi_dhat_stats_t, internal_bytes)
  MI_RS_CONST(MI_DHAT_STATS_VERSION)

  /* ---- include/mimalloc/memory-events.h ---- */
  MI_RS_SIZEOF(mi_memory_change_t)
  MI_RS_OFFSET(mi_memory_change_t, kind)
  MI_RS_OFFSET(mi_memory_change_t, total_bytes)
  MI_RS_OFFSET(mi_memory_change_t, delta_bytes)
  MI_RS_OFFSET(mi_memory_change_t, request_size)

  MI_RS_SIZEOF(mi_memory_callbacks_t)
  MI_RS_OFFSET(mi_memory_callbacks_t, handlers)
  MI_RS_OFFSET(mi_memory_callbacks_t, args)

  MI_RS_SIZEOF(mi_memory_snapshot_t)
  MI_RS_OFFSET(mi_memory_snapshot_t, size)
  MI_RS_OFFSET(mi_memory_snapshot_t, version)
  MI_RS_OFFSET(mi_memory_snapshot_t, live_bytes)
  MI_RS_OFFSET(mi_memory_snapshot_t, accum_bytes)
  MI_RS_OFFSET(mi_memory_snapshot_t, live_count)
  MI_RS_OFFSET(mi_memory_snapshot_t, accum_count)

  MI_RS_CONST(MI_MEMORY_SNAPSHOT_VERSION)
  MI_RS_CONST(MI_MEMORY_ALLOCATE)
  MI_RS_CONST(MI_MEMORY_FREE)
  MI_RS_CONST(MI_MEMORY_RESIZE)
  MI_RS_CONST(MI_MEMORY_CHANGE_COUNT)

  /* ---- include/mimalloc.h: hole purging (issue #272, Bun parity P7b) ---- */
  MI_RS_SIZEOF(mi_purge_holes_stats_t)
  MI_RS_OFFSET(mi_purge_holes_stats_t, purged_bytes)
  MI_RS_OFFSET(mi_purge_holes_stats_t, purged_blocks)
  MI_RS_OFFSET(mi_purge_holes_stats_t, purged_bytes_total)
  MI_RS_OFFSET(mi_purge_holes_stats_t, discard_calls)
  MI_RS_OFFSET(mi_purge_holes_stats_t, reuse_calls)
  MI_RS_OFFSET(mi_purge_holes_stats_t, pages_freed)
  MI_RS_OFFSET(mi_purge_holes_stats_t, ineligible_pages)
  MI_RS_OFFSET(mi_purge_holes_stats_t, ineligible_bytes)
  MI_RS_OFFSET(mi_purge_holes_stats_t, ineligible_free_bytes)
  MI_RS_OFFSET(mi_purge_holes_stats_t, unformed_bytes)
  MI_RS_OFFSET(mi_purge_holes_stats_t, unformed_bytes_total)
  MI_RS_OFFSET(mi_purge_holes_stats_t, unformed_discard_calls)
  MI_RS_OFFSET(mi_purge_holes_stats_t, unformed_reuse_calls)
  MI_RS_OFFSET(mi_purge_holes_stats_t, pages_skipped)
  MI_RS_OFFSET(mi_purge_holes_stats_t, blocks_visited)
  MI_RS_OFFSET(mi_purge_holes_stats_t, full_sweeps)

  /* ---- include/mimalloc.h: mi_purge_all (issue #366) ---- */
  MI_RS_SIZEOF(mi_purge_all_report_t)
  MI_RS_OFFSET(mi_purge_all_report_t, arena_bytes)
  MI_RS_OFFSET(mi_purge_all_report_t, hole_bytes)
  MI_RS_OFFSET(mi_purge_all_report_t, theaps_swept)
  MI_RS_OFFSET(mi_purge_all_report_t, theaps_pending)
  MI_RS_OFFSET(mi_purge_all_report_t, theaps_orphaned)
  MI_RS_OFFSET(mi_purge_all_report_t, gated)
  MI_RS_OFFSET(mi_purge_all_report_t, complete)
  MI_RS_SIZEOF(mi_purge_flags_t)
  MI_RS_CONST(MI_PURGE_FORCE)
  MI_RS_CONST(MI_PURGE_OK)
  MI_RS_CONST(MI_PURGE_PARTIAL)
  MI_RS_CONST(MI_PURGE_BUSY)

  /* ---- include/mimalloc-stats.h ---- */
  MI_RS_SIZEOF(mi_stat_count_t)
  MI_RS_OFFSET(mi_stat_count_t, total)
  MI_RS_OFFSET(mi_stat_count_t, peak)
  MI_RS_OFFSET(mi_stat_count_t, current)
  MI_RS_SIZEOF(mi_stat_counter_t)
  MI_RS_OFFSET(mi_stat_counter_t, total)

  MI_RS_SIZEOF(mi_stats_t)
  MI_RS_OFFSET(mi_stats_t, size)
  MI_RS_OFFSET(mi_stats_t, version)
  /* Generated straight from the header's own field list, so a field added or reordered
     upstream shows up here without this file being touched -- and then fails the Rust
     test as a missing/moved key, which is exactly the intent. */
#define MI_STAT_COUNT(stat)     MI_RS_OFFSET(mi_stats_t, stat)
#define MI_STAT_COUNTER(stat)   MI_RS_OFFSET(mi_stats_t, stat)
  MI_STAT_FIELDS()
#undef MI_STAT_COUNT
#undef MI_STAT_COUNTER
  MI_RS_OFFSET(mi_stats_t, _stat_reserved)
  MI_RS_OFFSET(mi_stats_t, _stat_counter_reserved)
  MI_RS_OFFSET(mi_stats_t, malloc_bins)
  MI_RS_OFFSET(mi_stats_t, page_bins)
  MI_RS_OFFSET(mi_stats_t, chunk_bins)
  MI_RS_CONST(MI_STAT_VERSION)
  MI_RS_CONST(MI_BIN_HUGE)
  MI_RS_CONST(MI_CBIN_COUNT)

  MI_RS_SIZEOF(mi_subproc_id_t)

  /* ---- include/mimalloc.h: mi_option_t ----
     Positional and silently wrong when mirrored stale: the fork inserted thirteen
     enumerators (prof_*, memory_events, purge_zeroes, scavenger, purge_holes*) BEFORE
     `_mi_option_last`, so any Rust mirror copied from upstream sets a different option
     than the caller named. Every enumerator the Rust side mirrors is listed here. */
  MI_RS_OPTION(mi_option_show_errors)
  MI_RS_OPTION(mi_option_show_stats)
  MI_RS_OPTION(mi_option_verbose)
  MI_RS_OPTION(mi_option_deprecated_eager_commit)
  MI_RS_OPTION(mi_option_arena_eager_commit)
  MI_RS_OPTION(mi_option_purge_decommits)
  MI_RS_OPTION(mi_option_allow_large_os_pages)
  MI_RS_OPTION(mi_option_reserve_huge_os_pages)
  MI_RS_OPTION(mi_option_reserve_huge_os_pages_at)
  MI_RS_OPTION(mi_option_reserve_os_memory)
  MI_RS_OPTION(mi_option_deprecated_segment_cache)
  MI_RS_OPTION(mi_option_deprecated_page_reset)
  MI_RS_OPTION(mi_option_deprecated_abandoned_page_purge)
  MI_RS_OPTION(mi_option_deprecated_segment_reset)
  MI_RS_OPTION(mi_option_deprecated_eager_commit_delay)
  MI_RS_OPTION(mi_option_purge_delay)
  MI_RS_OPTION(mi_option_use_numa_nodes)
  MI_RS_OPTION(mi_option_disallow_os_alloc)
  MI_RS_OPTION(mi_option_os_tag)
  MI_RS_OPTION(mi_option_max_errors)
  MI_RS_OPTION(mi_option_max_warnings)
  MI_RS_OPTION(mi_option_deprecated_max_segment_reclaim)
  MI_RS_OPTION(mi_option_destroy_on_exit)
  MI_RS_OPTION(mi_option_arena_reserve)
  MI_RS_OPTION(mi_option_arena_purge_mult)
  MI_RS_OPTION(mi_option_deprecated_purge_extend_delay)
  MI_RS_OPTION(mi_option_disallow_arena_alloc)
  MI_RS_OPTION(mi_option_retry_on_oom)
  MI_RS_OPTION(mi_option_deprecated_visit_abandoned)
  MI_RS_OPTION(mi_option_guarded_min)
  MI_RS_OPTION(mi_option_guarded_max)
  MI_RS_OPTION(mi_option_guarded_precise)
  MI_RS_OPTION(mi_option_guarded_sample_rate)
  MI_RS_OPTION(mi_option_guarded_sample_seed)
  MI_RS_OPTION(mi_option_generic_collect)
  MI_RS_OPTION(mi_option_page_reclaim_on_free)
  MI_RS_OPTION(mi_option_page_full_retain)
  MI_RS_OPTION(mi_option_page_max_candidates)
  MI_RS_OPTION(mi_option_max_vabits)
  MI_RS_OPTION(mi_option_pagemap_commit)
  MI_RS_OPTION(mi_option_page_commit_on_demand)
  MI_RS_OPTION(mi_option_page_max_reclaim)
  MI_RS_OPTION(mi_option_page_cross_thread_max_reclaim)
  MI_RS_OPTION(mi_option_allow_thp)
  MI_RS_OPTION(mi_option_minimal_purge_size)
  MI_RS_OPTION(mi_option_arena_max_object_size)
  MI_RS_OPTION(mi_option_arena_is_numa_local)
  /* fork additions start here (indices 47..59) */
  MI_RS_OPTION(mi_option_prof)
  MI_RS_OPTION(mi_option_prof_sample_rate)
  MI_RS_OPTION(mi_option_prof_bt_max)
  MI_RS_OPTION(mi_option_prof_accum)
  MI_RS_OPTION(mi_option_prof_seed)
  MI_RS_OPTION(mi_option_prof_max_bytes)
  MI_RS_OPTION(mi_option_memory_events)
  MI_RS_OPTION(mi_option_purge_zeroes)
  MI_RS_OPTION(mi_option_scavenger)
  MI_RS_OPTION(mi_option_purge_holes)
  MI_RS_OPTION(mi_option_purge_holes_eager_zero)
  MI_RS_OPTION(mi_option_purge_holes_min_interval)
  MI_RS_OPTION(mi_option_purge_holes_full_every)
  MI_RS_OPTION(mi_option_snapshot_on_exit)
  MI_RS_OPTION(_mi_option_last)
  /* deprecated aliases, defined after the sentinel with explicit values */
  MI_RS_OPTION(mi_option_large_os_pages)
  MI_RS_OPTION(mi_option_eager_region_commit)
  MI_RS_OPTION(mi_option_reset_decommits)
  MI_RS_OPTION(mi_option_reset_delay)
  MI_RS_OPTION(mi_option_limit_os_alloc)
};

/* Returns the entry table and writes its length to `*count`. The table is static
   `const` data with static-string names; the caller never frees anything. */
/* #322: this probe's own export gets the same treatment as the API it checks -- the
   prototype src/sys.rs assumes, so the definition below is compared against it. It sits
   here rather than in the block above because it needs the entry typedef. */
const mi_rs_layout_entry_t* mi_rs_layout_table(size_t* count);

mi_decl_export const mi_rs_layout_entry_t* mi_rs_layout_table(size_t* count) mi_attr_noexcept {
  if (count != NULL) { *count = sizeof(mi_rs_layout_entries) / sizeof(mi_rs_layout_entries[0]); }
  return mi_rs_layout_entries;
}