Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concatenating two memory buffers without memcpy

In C I have a function foo(char *) that accepts a memory pointer. In the caller, I have two different memory buffers, which I need to concatenate so I can pass one pointer foo(). Is there a way for me to do that without actually copying one buffer to the end of the other buffer and without changing foo() itself? I.e make the two buffers appear as one virtual continuous buffer to foo()

I need this for performance reasons. An O(n) solution (where n is one of the buffers length) is not acceptable for my case.

Also, a Linux specific solution is fine, if it helps.

like image 489
Nir Avatar asked Jul 12 '26 04:07

Nir


2 Answers

This question seems to ask whether it is possible to concatenate the contents of two buffers (A and B) with the following constraints:

  • You can't copy the contents of A or B.
  • You can't change the address of A.
  • The operation must have a worst case complexity < O(n).
  • Presumably the address of B is such that A and B are not already concatenated. (As J.F. Sebastian pointed out in his answer, if you can allocate both A and B contiguously in the first place, you're done. But this seems like a degenerate case.)
  • You must be able to do this from a Linux kernel driver (see comment under Jerome's answer).
  • Neither A nor B is page aligned (see comment under original question).
  • Neither A nor B is a multiple of the page size (see comment under original question).

Given all that, my answer is no: it is not possible.

Yes, an OS kernel can use the CPU's MMU (memory management unit, on architectures that have one) to remap memory in either the kernel virtual address space or the user virtual address space. Allocate a contiguous chunk of virtual address space, then remap A and B into that buffer by modifying the page table entries for the chunk of virtual address space to point to the physical addresses of A and B.

This doesn't change the virtual address of A per se (since the old virtual address is still valid), but it does require you to access it through a different virtual address. This may be a problem.

The granularity of this remapping on today's typical CPU architectures is based on the page size(s), and since A and B are not page aligned nor are they a multiple of the page size, you will not be able to make them completely line up. This is definitely a problem.

Remapping N bytes requires modifying at least one page table entry for every M bytes, where M is the page size. This means that the remapping operation has a computational complexity of O(n) anyway. Other operations such as allocating more physical pages for page tables, flushing caches and TLBs, etc. would have additional performance implications.

Also, I'm wondering if the goal of this question somehow involves DMA (direct memory access). When performing DMA with an archaic device that requires contiguous memory, no amount of remapping is going to help unless you have an IOMMU at your disposal. And a modern device that can do scatter-gather DMA wouldn't require contiguous buffers in the first place.

like image 199
bk1e Avatar answered Jul 13 '26 18:07

bk1e


Yes, there is a way.

Allocate memory for the buffers in a such way that they are adjacent in memory.

Example:

char* a = malloc(a_size + b_size);
char* b = a + a_size;
like image 27
jfs Avatar answered Jul 13 '26 17:07

jfs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!