2011-06-03 Ivan Maidanski <ivmai@mail.ru>
[platform/upstream/libatomic_ops.git] / tests / test_malloc.c
1 /*
2  * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
3  * Original Author: Hans Boehm
4  *
5  * This file may be redistributed and/or modified under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2, or (at your option) any later version.
8  *
9  * It is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
12  * file doc/COPYING for more details.
13  */
14
15 #if defined(HAVE_CONFIG_H)
16 # include "config.h"
17 #endif
18
19 #include "run_parallel.inc"
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include "atomic_ops_malloc.h"
24
25 #ifndef MAX_NTHREADS
26 # define MAX_NTHREADS 100
27 #endif
28
29 #ifndef DEFAULT_NTHREADS
30 # ifdef HAVE_MMAP
31 #   define DEFAULT_NTHREADS 10
32 # else
33 #   define DEFAULT_NTHREADS 3
34 # endif
35 #endif
36
37 #ifndef N_REVERSALS
38 # define N_REVERSALS 1000 /* must be even */
39 #endif
40
41 #ifndef LIST_LENGTH
42 # define LIST_LENGTH 1000
43 #endif
44
45 #ifndef LARGE_OBJ_SIZE
46 # define LARGE_OBJ_SIZE 200000
47 #endif
48
49 #ifdef USE_STANDARD_MALLOC
50 # define AO_malloc(n) malloc(n)
51 # define AO_free(p) free(p)
52 # define AO_malloc_enable_mmap()
53 #endif
54
55 typedef struct list_node {
56         struct list_node *next;
57         int data;
58 } ln;
59
60 ln *cons(int d, ln *tail)
61 {
62   static size_t extra = 0;
63   size_t my_extra = extra;
64   ln *result;
65   int * extras;
66   int i;
67
68   if (my_extra > 100)
69     extra = my_extra = 0;
70   else
71     ++extra;
72   result = AO_malloc(sizeof(ln) + sizeof(int)*my_extra);
73   if (result == 0)
74     {
75       fprintf(stderr, "Out of memory\n");
76         /* Normal for more than about 10 threads without mmap? */
77       abort();
78     }
79
80   result -> data = d;
81   result -> next = tail;
82   extras = (int *)(result+1);
83   for (i = 0; i < my_extra; ++i) extras[i] = 42;
84   return result;
85 }
86
87 void print_list(ln *l)
88 {
89   ln *p;
90
91   for (p = l; p != 0; p = p -> next)
92     {
93       fprintf(stderr, "%d, ", p -> data);
94     }
95   fprintf(stderr, "\n");
96 }
97
98 /* Check that l contains numbers from m to n inclusive in ascending order */
99 void check_list(ln *l, int m, int n)
100 {
101   ln *p;
102   int i;
103
104   for (p = l, i = m; p != 0; p = p -> next, ++i)
105     {
106       if (i != p -> data)
107         {
108           fprintf(stderr, "Found %d, expected %d\n", p -> data, i);
109           abort();
110         }
111     }
112 }
113
114 /* Create a list of integers from m to n */
115 ln *
116 make_list(int m, int n)
117 {
118   if (m > n) return 0;
119   return cons(m, make_list(m+1, n));
120 }
121
122 /* Reverse list x, and concatenate it to y, deallocating no longer needed */
123 /* nodes in x.                                                            */
124 ln *
125 reverse(ln *x, ln *y)
126 {
127   ln * result;
128
129   if (x == 0) return y;
130   result = reverse(x -> next, cons(x -> data, y));
131   AO_free(x);
132   return result;
133 }
134
135 int dummy_test(void) { return 1; }
136
137 void * run_one_test(void * arg) {
138   ln * x = make_list(1, LIST_LENGTH);
139   int i;
140   char *p = AO_malloc(LARGE_OBJ_SIZE);
141   char *q;
142
143   if (0 == p) {
144 #   ifdef HAVE_MMAP
145       fprintf(stderr, "AO_malloc(%d) failed\n", LARGE_OBJ_SIZE);
146 #   else
147       fprintf(stderr, "AO_malloc(%d) failed: This is normal without mmap\n",
148               LARGE_OBJ_SIZE);
149 #   endif
150   } else {
151     p[0] = p[LARGE_OBJ_SIZE/2] = p[LARGE_OBJ_SIZE-1] = 'a';
152     q = AO_malloc(LARGE_OBJ_SIZE);
153     if (q == 0)
154       {
155         fprintf(stderr, "Out of memory\n");
156           /* Normal for more than about 10 threads without mmap? */
157         abort();
158       }
159     q[0] = q[LARGE_OBJ_SIZE/2] = q[LARGE_OBJ_SIZE-1] = 'b';
160     if (p[0] != 'a' || p[LARGE_OBJ_SIZE/2] != 'a'
161         || p[LARGE_OBJ_SIZE-1] != 'a') {
162       fprintf(stderr, "First large allocation smashed\n");
163       abort();
164     }
165     AO_free(p);
166     if (q[0] != 'b' || q[LARGE_OBJ_SIZE/2] != 'b'
167         || q[LARGE_OBJ_SIZE-1] != 'b') {
168       fprintf(stderr, "Second large allocation smashed\n");
169       abort();
170     }
171     AO_free(q);
172   }
173 # ifdef DEBUG_RUN_ONE_TEST
174     x = reverse(x, 0);
175     print_list(x);
176     x = reverse(x, 0);
177     print_list(x);
178 # endif
179   for (i = 0; i < N_REVERSALS; ++i) {
180     x = reverse(x, 0);
181   }
182   check_list(x, 1, LIST_LENGTH);
183   return 0;
184 }
185
186 int main(int argc, char **argv) {
187     int nthreads;
188
189     if (1 == argc) {
190       nthreads = DEFAULT_NTHREADS;
191     } else if (2 == argc) {
192       nthreads = atoi(argv[1]);
193       if (nthreads < 1 || nthreads > MAX_NTHREADS) {
194         fprintf(stderr, "Invalid # of threads argument\n");
195         exit(1);
196       }
197     } else {
198       fprintf(stderr, "Usage: %s [# of threads]\n", argv[0]);
199       exit(1);
200     }
201     printf("Performing %d reversals of %d element lists in %d threads\n",
202            N_REVERSALS, LIST_LENGTH, nthreads);
203     AO_malloc_enable_mmap();
204     run_parallel(nthreads, run_one_test, dummy_test, "AO_malloc/AO_free");
205     return 0;
206 }