{"push_id":621875372,"size":3,"distinct_size":3,"ref":"refs/heads/master","head":"37d60d970c342b7f21a173a363c8be6558ad6e6e","before":"a3d9ab5070b56b49aa91be2887fa5b118012b2cd","commits":[{"sha":"c26efef9798914e208329c0e8c3c73bb1135d9e3","author":{"email":"39ea6a09710987173e32e37c86918024a0f441c1@suse.de","name":"Mel Gorman"},"message":"malloc: Consistently apply trim_threshold to all heaps [BZ #17195]\n\nTrimming heaps is a balance between saving memory and the system overhead\nrequired to update page tables and discard allocated pages. The malloc\noption M_TRIM_THRESHOLD is a tunable that users are meant to use to decide\nwhere this balance point is but it is only applied to the main arena.\n\nFor scalability reasons, glibc malloc has per-thread heaps but these are\nshrunk with madvise() if there is one page free at the top of the heap.\nIn some circumstances this can lead to high system overhead if a thread\nhas a control flow like\n\n    while (data_to_process) {\n        buf = malloc(large_size);\n        do_stuff();\n        free(buf);\n    }\n\nFor a large size, the free() will call madvise (pagetable teardown, page\nfree and TLB flush) every time followed immediately by a malloc (fault,\nkernel page alloc, zeroing and charge accounting). The kernel overhead\ncan dominate such a workload.\n\nThis patch allows the user to tune when madvise gets called by applying\nthe trim threshold to the per-thread heaps and using similar logic to the\nmain arena when deciding whether to shrink. Alternatively if the dynamic\nbrk/mmap threshold gets adjusted then the new values will be obeyed by\nthe per-thread heaps.\n\nBug 17195 was a test case motivated by a problem encountered in scientific\napplications written in python that performance badly due to high page fault\noverhead. The basic operation of such a program was posted by Julian Taylor\nhttps://sourceware.org/ml/libc-alpha/2015-02/msg00373.html\n\nWith this patch applied, the overhead is eliminated. All numbers in this\nreport are in seconds and were recorded by running Julian's program 30\ntimes.\n\npyarray\n                                 glibc               madvise\n                                  2.21                    v2\nSystem  min             1.81 (  0.00%)        0.00 (100.00%)\nSystem  mean            1.93 (  0.00%)        0.02 ( 99.20%)\nSystem  stddev          0.06 (  0.00%)        0.01 ( 88.99%)\nSystem  max             2.06 (  0.00%)        0.03 ( 98.54%)\nElapsed min             3.26 (  0.00%)        2.37 ( 27.30%)\nElapsed mean            3.39 (  0.00%)        2.41 ( 28.84%)\nElapsed stddev          0.14 (  0.00%)        0.02 ( 82.73%)\nElapsed max             4.05 (  0.00%)        2.47 ( 39.01%)\n\n               glibc     madvise\n                2.21          v2\nUser          141.86      142.28\nSystem         57.94        0.60\nElapsed       102.02       72.66\n\nNote that almost a minutes worth of system time is eliminted and the\nprogram completes 28% faster on average.\n\nTo illustrate the problem without python this is a basic test-case for\nthe worst case scenario where every free is a madvise followed by a an alloc\n\n/* gcc bench-free.c -lpthread -o bench-free */\nstatic int num = 1024;\n\nvoid __attribute__((noinline,noclone)) dostuff (void *p)\n{\n}\n\nvoid *worker (void *data)\n{\n  int i;\n\n  for (i = num; i--;)\n    {\n      void *m = malloc (48*4096);\n      dostuff (m);\n      free (m);\n    }\n\n  return NULL;\n}\n\nint main()\n{\n  int i;\n  pthread_t t;\n  void *ret;\n  if (pthread_create (&t, NULL, worker, NULL))\n    exit (2);\n  if (pthread_join (t, &ret))\n    exit (3);\n  return 0;\n}\n\nBefore the patch, this resulted in 1024 calls to madvise. With the patch applied,\nmadvise is called twice because the default trim threshold is high enough to avoid\nthis.\n\nThis a more complex case where there is a mix of frees. It's simply a different worker\nfunction for the test case above\n\nvoid *worker (void *data)\n{\n  int i;\n  int j = 0;\n  void *free_index[num];\n\n  for (i = num; i--;)\n    {\n      void *m = malloc ((i % 58) *4096);\n      dostuff (m);\n      if (i % 2 == 0) {\n        free (m);\n      } else {\n        free_index[j++] = m;\n      }\n    }\n  for (; j >= 0; j--)\n    {\n      free(free_index[j]);\n    }\n\n  return NULL;\n}\n\nglibc 2.21 calls malloc 90305 times but with the patch applied, it's\ncalled 13438. Increasing the trim threshold will decrease the number of\ntimes it's called with the option of eliminating the overhead.\n\nebizzy is meant to generate a workload resembling common web application\nserver workloads. It is threaded with a large working set that at its core\nhas an allocation, do_stuff, free loop that also hits this case. The primary\nmetric of the benchmark is records processed per second. This is running on\nmy desktop which is a single socket machine with an I7-4770 and 8 cores.\nEach thread count was run for 30 seconds. It was only run once as the\nperformance difference is so high that the variation is insignificant.\n\n                glibc 2.21              patch\nthreads 1            10230              44114\nthreads 2            19153              84925\nthreads 4            34295             134569\nthreads 8            51007             183387\n\nNote that the saving happens to be a concidence as the size allocated\nby ebizzy was less than the default threshold. If a different number of\nchunks were specified then it may also be necessary to tune the threshold\nto compensate\n\nThis is roughly quadrupling the performance of this benchmark. The difference in\nsystem CPU usage illustrates why.\n\nebizzy running 1 thread with glibc 2.21\n10230 records/s 306904\nreal 30.00 s\nuser  7.47 s\nsys  22.49 s\n\n22.49 seconds was spent in the kernel for a workload runinng 30 seconds. With the\npatch applied\n\nebizzy running 1 thread with patch applied\n44126 records/s 1323792\nreal 30.00 s\nuser 29.97 s\nsys   0.00 s\n\nsystem CPU usage was zero with the patch applied. strace shows that glibc\nrunning this workload calls madvise approximately 9000 times a second. With\nthe patch applied madvise was called twice during the workload (or 0.06\ntimes per second).\n\n2015-02-10  Mel Gorman  <mgorman@suse.de>\n\n  [BZ #17195]\n  * malloc/arena.c (free): Apply trim threshold to per-thread heaps\n    as well as the main arena.","distinct":true,"url":"https://api.github.com/repos/bminor/glibc/commits/c26efef9798914e208329c0e8c3c73bb1135d9e3"},{"sha":"b763f6ae859ecea70a5dacb8ad45c71d5f667e2e","author":{"email":"c9df6394cb541f693236245820fbe23866f1a3fe@suse.de","name":"Andreas Schwab"},"message":"aarch64: Increase MINSIGSTKSZ and SIGSTKSZ (bug 16850)","distinct":true,"url":"https://api.github.com/repos/bminor/glibc/commits/b763f6ae859ecea70a5dacb8ad45c71d5f667e2e"},{"sha":"37d60d970c342b7f21a173a363c8be6558ad6e6e","author":{"email":"a228da394793d2e6e5b1b6a5525945d856f25556@redhat.com","name":"Florian Weimer"},"message":"Define libc_max_align_t for internal use","distinct":true,"url":"https://api.github.com/repos/bminor/glibc/commits/37d60d970c342b7f21a173a363c8be6558ad6e6e"}]}