s117 / anycore-riscv

The AnyCore toolset targetting the RISC-V ISA
Other
0 stars 0 forks source link

Newlib toolchain has issue with large malloc request. #2

Closed s117 closed 4 years ago

s117 commented 4 years ago

Some SPEC benchmark like 657.xz requires a large amount of memory. But some weird memory allocator behavior is observed with the newlib 9.2.0 toolchain:

No matter how much physical is simulated (for example, 16GB, spike -m16384 ...)

  1. malloc with a large size (about >2GB) always returns null.

  2. after the program has requested more than 2GB memory (roughly), malloc always returns null.

A test code snippet:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>

void bulk_test() {
  printf("\n\n**************** Test large heap memory allocation - In bulk ****************\n\n");
  const size_t alloc_size = (8192ul << 20); // 8192 MB
  printf("Allocating %"
  PRIu64
  " MB buffer\n", (alloc_size >> 20));

  void *test_buf = malloc(alloc_size);
  printf("test buf = %p\n", test_buf);
  if (test_buf) {
    free(test_buf);
  }
}

void chunk_test() {
  printf("\n\n**************** Test large heap memory allocation - In slices ****************\n\n");
  const size_t slice_size = (1024ul << 20);
  const int n_slices = 10; // 10 slices, 1024 MB each
  void *test_buf[n_slices];
  printf("Allocating %d %"
  PRIu64
  " MB slices...\n", n_slices, (slice_size >> 20));
  for (int i = 0; i < n_slices; i++) {
    test_buf[i] = malloc(slice_size);
    printf("%dth %llu MB test buf = %p\n", i, slice_size >> 20, test_buf[i]);
  }

  for (int i = 0; i < n_slices; i++) {
    if (test_buf[i]) {
      free(test_buf[i]);
    }
  }
}

int main() {
  bulk_test();
  chunk_test();
  return 0;
}
s117 commented 4 years ago

The above two behaviors have two different causes accordingly:

  1. The newlib's malloc implementation contains a too conservative overflow checking. Which limits the size of a single malloc request to 2GB. It is patched by https://github.com/s117/riscv-newlib/commit/0e3a7a5f01514d617bccce9dbb34380088d4c9da

  2. PK clamps the vaddr of the user stack top to 0x80000000. I guess the reason is for RV32 compatibility. But this effectively limited the brk line cannot go over 0x8000000, and the result is the maximum available heap space is less than 2G. It is patched by https://github.com/s117/riscv-pk/commit/b142a14ae3ed8117862636f56f970a8775599356

The above patches were incorporated by commit 6fb31c8.