Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: libc: common: Export z_malloc_heap #79123

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

d3zd3z
Copy link
Collaborator

@d3zd3z d3zd3z commented Sep 27, 2024

The heap used by malloc/free is a static, private to the malloc implementation. Unfortunately, this makes it impossible to use tools like sys_heap_runtime_stats_get(), as they need access to the heap variable.

Remedy this by removing the static from this declaration.

Other options are to add an additional API to make the desired queries.

The heap used by malloc/free is a static, private to the malloc
implementation.  Unfortunately, this makes it impossible to use tools
like `sys_heap_runtime_stats_get()`, as they need access to the heap
variable.

Remedy this by removing the static from this declaration.

Signed-off-by: David Brown <david.brown@linaro.org>
@zephyrbot zephyrbot added size: XS A PR changing only a single line of code area: C Library C Standard Library labels Sep 27, 2024
@cfriedt
Copy link
Member

cfriedt commented Sep 27, 2024

Personally, I would like to see mallinfo() implemented in Zephyr (and it has been attempted previously).

Would that help?

@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Oct 1, 2024

Personally, I would like to see mallinfo() implemented in Zephyr (and it has been attempted previously).

Would that help?

Having mallinfo() would definitely work for my purposes. I think you might only be able to fill in some of the fields, though.

@cfriedt
Copy link
Member

cfriedt commented Oct 1, 2024

Having mallinfo() would definitely work for my purposes. I think you might only be able to fill in some of the fields, though.

I'll whip up a PR

Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change is fine; symbol already had a prefix so can appear in the general link.

No opinion on implementing mallinfo() per se. Quickly checking the man page it's pretty glibc-specific, but the basic stuff is reasonably portable.

@cfriedt
Copy link
Member

cfriedt commented Oct 2, 2024

a discord conversation concluded that mallinfo is not sufficient for David's purposes, so I'll stamp this as well.

@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Oct 2, 2024

The problem with mallinfo is that is basically a dump of glibc malloc internals. I think we're better of just providing the Zephyr heap stats. Exporting this allows someone to do that on their own, or we could write wrappers. But, the symbol already has the prefix.

Copy link
Collaborator

@keith-packard keith-packard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to declare this in some header file?

@cfriedt
Copy link
Member

cfriedt commented Oct 2, 2024

With the heap listener API, I think the last time I looked at it, it only allowed for one listener. It might have been more of an implementation detail though, because the API itself looks capable of supporting many.

If that limitation weren't present, it would be trivial to support any number of decent frontends for recording / tracing allocation events (for various definitions of decent).

@stephanosio
Copy link
Member

The problem with mallinfo is that is basically a dump of glibc malloc internals. I think we're better of just providing the Zephyr heap stats.

@d3zd3z What prevents us from defining our own struct mallinfo with the exact fields we need? It is a non-standard function after all -- we do not need to align with the Linux struct mallinfo and there is nothing preventing us from defining Zephyr-flavoured mallinfo().

Z_LIBC_DATA static struct sys_heap z_malloc_heap;
Z_LIBC_DATA struct sys_heap z_malloc_heap;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this can be useful for debugging purposes; but, this more or less creates an implicit contract between an internal implementation detail of common libc and whatever will be using this (another Zephyr component? user application?), and I anticipate we will be seeing bugs like "unresolved symbol z_malloc_heap" (or even worse "sys_heap_runtime_stats_get crashing because z_malloc_heap is no longer struct sys_heap") in the future if we do this.

I would say we should define and implement Zephyr-flavoured mallinfo with the fields we need if we want to make the internal heap stats available to the components external to the common libc; otherwise, patches/hacks like these should stay in one's local branch.

@cfriedt
Copy link
Member

cfriedt commented Oct 3, 2024

What prevents us from defining our own struct mallinfo with the exact fields we need? It is a non-standard function after all -- we do not need to align with the Linux struct mallinfo and there is nothing preventing us from defining Zephyr-flavoured mallinfo().

Technically, we could also make accessor functions to abstract things, removing the need for duplicate code everywhere. E.g.

// struct mallinfo could have custom fields appended (e.g. uintptr_t).

// These could all be either real functions or inline

size_t mallinfo_get_avail_buckets(const struct mallinfo *info);
size_t mallinfo_get_free_bytes(const struct mallinfo *info);
size_t mallinfo_get_allocated_bytes(const struct mallinfo *info);
size_t mallinfo_get_max_allocated_bytes(const struct mallinfo *info);

// maybe a bucket accessor for testing or debug?
struct z_heap_bucket* mallinfo_get_bucket(can nst struct mallinfo *info, size_t index);

@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Oct 4, 2024

I don't see a lot of benefit to adding the accessors. @cfriedt what do you think of pushing your mallinfo change, but just with fields that make sense for us (I'm even ok with the ifdefs, especially since it will make it clear to someone using the header what features they need to be able to get the information).

@cfriedt
Copy link
Member

cfriedt commented Oct 4, 2024

I don't see a lot of benefit to adding the accessors. @cfriedt what do you think of pushing your mallinfo change, but just with fields that make sense for us

@d3zd3z let's start with what you need here in order to for you to make progress.

What fields make sense / are important for you to see?

@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Oct 8, 2024

I don't see a lot of benefit to adding the accessors. @cfriedt what do you think of pushing your mallinfo change, but just with fields that make sense for us

@d3zd3z let's start with what you need here in order to for you to make progress.

What fields make sense / are important for you to see?

Well, to "make progress", I just remove the 'static', but I'd rather not keep that patch locally. I'm inclined to define our own mallinfo. The main problem with separate accessors is that they aren't atomic, and might return inconsistent data if there are allocation operations between the calls (say between threads).

@keith-packard
Copy link
Collaborator

Frankly, I'd like to see a general migration from custom malloc implementations to the common one. In that case, exposing the fact that it uses the standard Zephyr heap manager seems completely reasonable to me. Trying to construct new interfaces to hide the implementation doesn't seem valuable for the long term. Do we need patches that replace the newlib allocator with the common one? Are there other C library allocators in common use?

@cfriedt
Copy link
Member

cfriedt commented Oct 8, 2024

What fields make sense / are important for you to see?

Well, to "make progress", I just remove the 'static', but I'd rather not keep that patch locally but I'd rather not keep that patch locally

Stephanos wouldn't approve that though, so let's find the next best compromise.

The main problem with separate accessors is that they aren't atomic

Accessors to a copy of a mallinfo on the stack don't need to be atomic but, in retrospect, that would be kind of annoying anyway to have one accessor per field. Not a great suggestion. My bad.

I'm inclined to define our own mallinfo.

Let's start there - think that would make sense as long as there isn't a naming conflict. We don't need to support the GNU interface, but if someone else wants to implement it, they can in the future.

What about this?

// return a copy of the heap on the stack.
// copy is made atomically.
// mallinfoZ == z_heap, or some other derivative
struct mallinfoZ mallinfoZ(void);

I'm not crazy about giving users all of the heap bucket pointers. Ideally, we could minimize the surface that footgun points at.

Would it make sense to provide a subset of z_heap? Like the info from CONFIG_SYS_HEAP_RUNTIME_STATS? Maybe the heap size, additionally?

struct mallinfoZ {
  size_t size_bytes;
  size_t free_bytes;
  size_t allocated_bytes;
  size_t max_allocated_bytes;
};

If users want something similar to the gnu mallinfo2, it's more of a future problem. As long as there is separation, it's fine.

@d3zd3z
Copy link
Collaborator Author

d3zd3z commented Oct 9, 2024

What about this?

I'm not particularly fond of mallinfoZ, maybe z_mallinfo? I do like having readable field names, though.

My usage is pretty simple. I have something that every 10 minutes or so prints out the malloc infomation, namely to make sure I don't have memory leaks.

@cfriedt
Copy link
Member

cfriedt commented Oct 9, 2024

That works for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: C Library C Standard Library size: XS A PR changing only a single line of code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants