1a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany#include <stdio.h>
2a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany#include <vector>
3a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany#include <pthread.h>
4a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany#include <malloc.h>
5a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany#include <algorithm>
6a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany
7a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryanyusing namespace std;
8a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany
9a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryanyconst size_t kNumThreds = 16;
10abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukovconst size_t kNumIters = 1 << 23;
11a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany
123ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryanyinline void break_optimization(void *arg) {
133ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany  __asm__ __volatile__("" : : "r" (arg) : "memory");
143ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany}
153ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany
163ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany__attribute__((noinline))
171045df665c7b314991fbdbe0eadd11b003574a04Kostya Serebryanystatic void *MallocThread(void *t) {
18a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  size_t total_malloced = 0, total_freed = 0;
19a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  size_t max_in_use = 0;
20a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  size_t tid = reinterpret_cast<size_t>(t);
21a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  vector<pair<char *, size_t> > allocated;
22a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  allocated.reserve(kNumIters);
23a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  for (size_t i = 1; i < kNumIters; i++) {
24abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukov    if ((i % (kNumIters / 4)) == 0 && tid == 0)
25a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      fprintf(stderr, "   T[%ld] iter %ld\n", tid, i);
26abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukov    bool allocate = (i % 5) <= 2;  // 60% malloc, 40% free
27abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukov    if (i > kNumIters / 4)
28abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukov      allocate = i % 2;  // then switch to 50% malloc, 50% free
29abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukov    if (allocate) {
30a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      size_t size = 1 + (i % 200);
31a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      if ((i % 10001) == 0)
32a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany        size *= 4096;
33a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      total_malloced += size;
34a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      char *x = new char[size];
35a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      x[0] = x[size - 1] = x[size / 2] = 0;
36a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      allocated.push_back(make_pair(x, size));
37a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      max_in_use = max(max_in_use, total_malloced - total_freed);
38abb1febb6046fbc5fc30c7872dd06b27d0fb51f9Dmitry Vyukov    } else {
39a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      if (allocated.empty()) continue;
40a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      size_t slot = i % allocated.size();
41a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      char *p = allocated[slot].first;
4209575a176caef64cf43f3eac8e197ee4f55572bdDmitry Vyukov      p[0] = 0;  // emulate last user touch of the block
43a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      size_t size = allocated[slot].second;
44a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      total_freed += size;
45a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      swap(allocated[slot], allocated.back());
46a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      allocated.pop_back();
47a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany      delete [] p;
48a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany    }
49a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  }
50a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  if (tid == 0)
51a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany    fprintf(stderr, "   T[%ld] total_malloced: %ldM in use %ldM max %ldM\n",
52a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany           tid, total_malloced >> 20, (total_malloced - total_freed) >> 20,
53a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany           max_in_use >> 20);
54a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  for (size_t i = 0; i < allocated.size(); i++)
55a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany    delete [] allocated[i].first;
56a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  return 0;
57a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany}
58a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany
593ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryanytemplate <int depth>
603ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryanystruct DeepStack {
613ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany  __attribute__((noinline))
623ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany  static void *run(void *t) {
633ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    break_optimization(0);
643ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    DeepStack<depth - 1>::run(t);
653ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    break_optimization(0);
663ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    return 0;
673ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany  }
683ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany};
693ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany
703ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryanytemplate<>
713ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryanystruct DeepStack<0> {
723ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany  static void *run(void *t) {
733ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    MallocThread(t);
743ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    return 0;
753ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany  }
763ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany};
773ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany
781045df665c7b314991fbdbe0eadd11b003574a04Kostya Serebryany// Build with -Dstandalone_malloc_test=main to make it a separate program.
791045df665c7b314991fbdbe0eadd11b003574a04Kostya Serebryanyint standalone_malloc_test() {
80a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  pthread_t t[kNumThreds];
81a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  for (size_t i = 0; i < kNumThreds; i++)
823ede807f3a02bdbcebf3e635bf2aeacf1c0082bdKostya Serebryany    pthread_create(&t[i], 0, DeepStack<200>::run, reinterpret_cast<void *>(i));
83a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  for (size_t i = 0; i < kNumThreds; i++)
84a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany    pthread_join(t[i], 0);
85a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany  malloc_stats();
860b9218ab2b68401673c5d6225c9833bd58003ed4Kostya Serebryany  return 0;
87a62440a464092ece8c068b57214ad3d13ec39b4bKostya Serebryany}
88