mall 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +6 -0
- data/.gitignore +13 -0
- data/.olddoc.yml +4 -0
- data/COPYING +165 -0
- data/GIT-VERSION-GEN +40 -0
- data/GNUmakefile +12 -0
- data/Gemfile +6 -0
- data/LICENSE +18 -0
- data/README +88 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/mall/.gitignore +5 -0
- data/ext/mall/extconf.rb +12 -0
- data/ext/mall/mall.c +301 -0
- data/ext/mall/mall.c.erb +246 -0
- data/mall.gemspec +21 -0
- data/pkg.mk +150 -0
- data/setup.rb +1585 -0
- data/test/test_mall.rb +66 -0
- metadata +76 -0
data/ext/mall/mall.c
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include <malloc.h>
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
static VALUE sym_arena;
|
|
8
|
+
|
|
9
|
+
static VALUE sym_ordblks;
|
|
10
|
+
|
|
11
|
+
static VALUE sym_smblks;
|
|
12
|
+
|
|
13
|
+
static VALUE sym_hblks;
|
|
14
|
+
|
|
15
|
+
static VALUE sym_hblkhd;
|
|
16
|
+
|
|
17
|
+
static VALUE sym_usmblks;
|
|
18
|
+
|
|
19
|
+
static VALUE sym_fsmblks;
|
|
20
|
+
|
|
21
|
+
static VALUE sym_uordblks;
|
|
22
|
+
|
|
23
|
+
static VALUE sym_fordblks;
|
|
24
|
+
|
|
25
|
+
static VALUE sym_keepcost;
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* call-seq:
|
|
30
|
+
* Mall.info -> hash
|
|
31
|
+
*
|
|
32
|
+
* Returns a hash with the following keys:
|
|
33
|
+
*
|
|
34
|
+
* :arena - bytes allocated via sbrk() (and not mmap())
|
|
35
|
+
* :ordblks - number of free (unused) chunks
|
|
36
|
+
* :smblks - number of fastbin blocks[1]
|
|
37
|
+
* :hblks - number of allocated mmap()-ed regions
|
|
38
|
+
* :hblkhd - bytes allocated in mmap()-ed regions
|
|
39
|
+
* :usmblks - maximum total allocated space[1]
|
|
40
|
+
* :fsmblks - space available in freed fastbin blocks[1]
|
|
41
|
+
* :uordblks - total allocated space in use
|
|
42
|
+
* :fordblks - total free space
|
|
43
|
+
* :keepcost - top-most, releasable (via malloc_trim) space
|
|
44
|
+
*
|
|
45
|
+
* All values are limited to 32-bit integers. This uses the limited
|
|
46
|
+
* mallinfo(3) function, consider using Mall.xml and parsing its output
|
|
47
|
+
* if you are using glibc (2.10+) with malloc_info(3)
|
|
48
|
+
*
|
|
49
|
+
* See also:
|
|
50
|
+
* http:// gnu.org/software/libc/manual/html_node/Statistics-of-Malloc.html
|
|
51
|
+
*
|
|
52
|
+
* [1] - this key is unused by glibc (ptmalloc2)
|
|
53
|
+
*/
|
|
54
|
+
static VALUE info(VALUE klass)
|
|
55
|
+
{
|
|
56
|
+
VALUE rv = rb_hash_new();
|
|
57
|
+
struct mallinfo stats = mallinfo(); /* whee aggregate returns :( */
|
|
58
|
+
|
|
59
|
+
#define MALLINFO_SET(KEY) \
|
|
60
|
+
rb_hash_aset(rv, sym_##KEY, INT2FIX(stats.KEY))
|
|
61
|
+
|
|
62
|
+
MALLINFO_SET(arena);
|
|
63
|
+
MALLINFO_SET(ordblks);
|
|
64
|
+
MALLINFO_SET(smblks);
|
|
65
|
+
MALLINFO_SET(hblks);
|
|
66
|
+
MALLINFO_SET(hblkhd);
|
|
67
|
+
MALLINFO_SET(usmblks);
|
|
68
|
+
MALLINFO_SET(fsmblks);
|
|
69
|
+
MALLINFO_SET(uordblks);
|
|
70
|
+
MALLINFO_SET(fordblks);
|
|
71
|
+
MALLINFO_SET(keepcost);
|
|
72
|
+
#undef MALLINFO_SET
|
|
73
|
+
return rv;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/*
|
|
77
|
+
* call-seq:
|
|
78
|
+
* Mall.opt(Mall::MMAP_THRESHOLD, 128 * 1024)
|
|
79
|
+
*
|
|
80
|
+
* some malloc implementations may not like mallopt() being called after
|
|
81
|
+
* malloc has been initialized (first call to malloc()). This is not
|
|
82
|
+
* the case with glibc malloc.
|
|
83
|
+
*
|
|
84
|
+
* See also:
|
|
85
|
+
* http://gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html
|
|
86
|
+
*/
|
|
87
|
+
static VALUE opt(VALUE klass, VALUE param, VALUE value)
|
|
88
|
+
{
|
|
89
|
+
int rv = mallopt(FIX2INT(param), FIX2INT(value));
|
|
90
|
+
|
|
91
|
+
return rv == 0 ? Qfalse : Qtrue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#ifdef HAVE_MALLOC_TRIM
|
|
95
|
+
/*
|
|
96
|
+
* call-seq:
|
|
97
|
+
* Mall.trim(pad) => true or false
|
|
98
|
+
*
|
|
99
|
+
* Attempt to trim off the top of the heap and release it back to
|
|
100
|
+
* the OS. +pad+ represents the amount of free space (in bytes) to
|
|
101
|
+
* leave unreleased for future allocations.
|
|
102
|
+
*
|
|
103
|
+
* Returns true if memory was released and false if not.
|
|
104
|
+
*
|
|
105
|
+
* This method is glibc-specific.
|
|
106
|
+
*/
|
|
107
|
+
static VALUE trim(VALUE klass, VALUE pad)
|
|
108
|
+
{
|
|
109
|
+
unsigned long tmp = NUM2ULONG(pad);
|
|
110
|
+
int rv = malloc_trim((size_t)tmp);
|
|
111
|
+
|
|
112
|
+
return rv == 1 ? Qtrue : Qfalse;
|
|
113
|
+
return Qfalse;
|
|
114
|
+
}
|
|
115
|
+
#endif /* HAVE_MALLOC_TRIM */
|
|
116
|
+
|
|
117
|
+
#ifdef HAVE_MALLOC_STATS
|
|
118
|
+
/*
|
|
119
|
+
* call-seq:
|
|
120
|
+
* Mall.dump_stats
|
|
121
|
+
*
|
|
122
|
+
* Dump malloc stats to STDERR
|
|
123
|
+
*
|
|
124
|
+
* This calls malloc_stats() internally, a function that is glibc-specific
|
|
125
|
+
*/
|
|
126
|
+
static VALUE dump_stats(VALUE klass)
|
|
127
|
+
{
|
|
128
|
+
fflush(stderr);
|
|
129
|
+
malloc_stats();
|
|
130
|
+
fflush(stderr);
|
|
131
|
+
return Qnil;
|
|
132
|
+
}
|
|
133
|
+
#endif /* HAVE_MALLOC_STATS */
|
|
134
|
+
|
|
135
|
+
#ifdef HAVE_MALLOC_INFO
|
|
136
|
+
static ID id_ltlt;
|
|
137
|
+
#include <errno.h>
|
|
138
|
+
static void xmlerr(FILE *fp, int err, const char *msg)
|
|
139
|
+
{
|
|
140
|
+
fclose(fp);
|
|
141
|
+
errno = err ? err : EIO; /* gotta have something */
|
|
142
|
+
rb_sys_fail(msg);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* call-seq:
|
|
147
|
+
* Mall.xml -> XML string
|
|
148
|
+
* Mall.xml(options = 0, io = $stderr) -> io
|
|
149
|
+
*
|
|
150
|
+
* Called with no arguments, this returns an XML string suitable for
|
|
151
|
+
* parsing with your favorite XML parser.
|
|
152
|
+
*
|
|
153
|
+
* If specified, +options+ must currently be +0+, but is reserved for
|
|
154
|
+
* future expansion.
|
|
155
|
+
*
|
|
156
|
+
* The second optional argument may be any object that responds to "<<"
|
|
157
|
+
* so it may be an IO, Array, StringIO, or String object among other
|
|
158
|
+
* things.
|
|
159
|
+
*
|
|
160
|
+
* This relies on malloc_info(3) which is only in glibc 2.10+
|
|
161
|
+
*/
|
|
162
|
+
static VALUE xml(int argc, VALUE *argv, VALUE self)
|
|
163
|
+
{
|
|
164
|
+
int err;
|
|
165
|
+
long len;
|
|
166
|
+
VALUE options, out, buf;
|
|
167
|
+
int xoptions;
|
|
168
|
+
FILE *fp;
|
|
169
|
+
|
|
170
|
+
rb_scan_args(argc, argv, "02", &options, &out);
|
|
171
|
+
xoptions = NIL_P(options) ? 0 : NUM2INT(options);
|
|
172
|
+
|
|
173
|
+
fp = tmpfile();
|
|
174
|
+
if (fp == NULL)
|
|
175
|
+
rb_sys_fail("tmpfile");
|
|
176
|
+
|
|
177
|
+
err = malloc_info(xoptions, fp);
|
|
178
|
+
if (err != 0)
|
|
179
|
+
xmlerr(fp, err, "malloc_info");
|
|
180
|
+
|
|
181
|
+
len = ftell(fp);
|
|
182
|
+
if (len < 0)
|
|
183
|
+
xmlerr(fp, errno, "ftell");
|
|
184
|
+
|
|
185
|
+
rewind(fp);
|
|
186
|
+
buf = rb_str_new(0, len);
|
|
187
|
+
if (fread(RSTRING_PTR(buf), 1, len, fp) != (size_t)len)
|
|
188
|
+
xmlerr(fp, ferror(fp), "fread");
|
|
189
|
+
fclose(fp);
|
|
190
|
+
|
|
191
|
+
if (NIL_P(out))
|
|
192
|
+
return buf;
|
|
193
|
+
return rb_funcall(out, id_ltlt, 1, buf);
|
|
194
|
+
}
|
|
195
|
+
#endif /* HAVE_MALLOC_INFO */
|
|
196
|
+
|
|
197
|
+
/*
|
|
198
|
+
* Mall is a single module with several singleton methods, most of which
|
|
199
|
+
* are glibc-specific. All constants may be used as the first argument
|
|
200
|
+
* to Mall.opt.
|
|
201
|
+
*/
|
|
202
|
+
void Init_mall(void)
|
|
203
|
+
{
|
|
204
|
+
VALUE mMall = rb_define_module("Mall");
|
|
205
|
+
rb_define_singleton_method(mMall, "opt", opt, 2);
|
|
206
|
+
rb_define_singleton_method(mMall, "info", info, 0);
|
|
207
|
+
#ifdef HAVE_MALLOC_TRIM
|
|
208
|
+
rb_define_singleton_method(mMall, "trim", trim, 1);
|
|
209
|
+
#endif /* HAVE_MALLOC_TRIM */
|
|
210
|
+
#ifdef HAVE_MALLOC_STATS
|
|
211
|
+
rb_define_singleton_method(mMall, "dump_stats", dump_stats, 0);
|
|
212
|
+
#endif /* HAVE_MALLOC_STATS */
|
|
213
|
+
#ifdef HAVE_MALLOC_INFO
|
|
214
|
+
id_ltlt = rb_intern("<<");
|
|
215
|
+
rb_define_singleton_method(mMall, "xml", xml, -1);
|
|
216
|
+
#endif /* HAVE_MALLOC_INFO*/
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
sym_arena = ID2SYM(rb_intern("arena"));
|
|
220
|
+
|
|
221
|
+
sym_ordblks = ID2SYM(rb_intern("ordblks"));
|
|
222
|
+
|
|
223
|
+
sym_smblks = ID2SYM(rb_intern("smblks"));
|
|
224
|
+
|
|
225
|
+
sym_hblks = ID2SYM(rb_intern("hblks"));
|
|
226
|
+
|
|
227
|
+
sym_hblkhd = ID2SYM(rb_intern("hblkhd"));
|
|
228
|
+
|
|
229
|
+
sym_usmblks = ID2SYM(rb_intern("usmblks"));
|
|
230
|
+
|
|
231
|
+
sym_fsmblks = ID2SYM(rb_intern("fsmblks"));
|
|
232
|
+
|
|
233
|
+
sym_uordblks = ID2SYM(rb_intern("uordblks"));
|
|
234
|
+
|
|
235
|
+
sym_fordblks = ID2SYM(rb_intern("fordblks"));
|
|
236
|
+
|
|
237
|
+
sym_keepcost = ID2SYM(rb_intern("keepcost"));
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
#ifdef M_MXFAST
|
|
242
|
+
/* max request size for "fastbins" */
|
|
243
|
+
rb_define_const(mMall, "MXFAST", INT2FIX(M_MXFAST));
|
|
244
|
+
#endif
|
|
245
|
+
|
|
246
|
+
#ifdef M_NLBLKS
|
|
247
|
+
/* unused in glibc */
|
|
248
|
+
rb_define_const(mMall, "NLBLKS", INT2FIX(M_NLBLKS));
|
|
249
|
+
#endif
|
|
250
|
+
|
|
251
|
+
#ifdef M_GRAIN
|
|
252
|
+
/* unused in glibc */
|
|
253
|
+
rb_define_const(mMall, "GRAIN", INT2FIX(M_GRAIN));
|
|
254
|
+
#endif
|
|
255
|
+
|
|
256
|
+
#ifdef M_KEEP
|
|
257
|
+
/* unused in glibc */
|
|
258
|
+
rb_define_const(mMall, "KEEP", INT2FIX(M_KEEP));
|
|
259
|
+
#endif
|
|
260
|
+
|
|
261
|
+
#ifdef M_TRIM_THRESHOLD
|
|
262
|
+
/* maximum amount of unused memory at the top of the heapto keep before releasing it back to the kernel */
|
|
263
|
+
rb_define_const(mMall, "TRIM_THRESHOLD", INT2FIX(M_TRIM_THRESHOLD));
|
|
264
|
+
#endif
|
|
265
|
+
|
|
266
|
+
#ifdef M_TOP_PAD
|
|
267
|
+
/* amount of extra space to allocate when allocating from the heap */
|
|
268
|
+
rb_define_const(mMall, "TOP_PAD", INT2FIX(M_TOP_PAD));
|
|
269
|
+
#endif
|
|
270
|
+
|
|
271
|
+
#ifdef M_MMAP_THRESHOLD
|
|
272
|
+
/* the request size threshold for using mmap() (instead of sbrk()) */
|
|
273
|
+
rb_define_const(mMall, "MMAP_THRESHOLD", INT2FIX(M_MMAP_THRESHOLD));
|
|
274
|
+
#endif
|
|
275
|
+
|
|
276
|
+
#ifdef M_MMAP_MAX
|
|
277
|
+
/* the maximum number of active mmap() requests in use at once */
|
|
278
|
+
rb_define_const(mMall, "MMAP_MAX", INT2FIX(M_MMAP_MAX));
|
|
279
|
+
#endif
|
|
280
|
+
|
|
281
|
+
#ifdef M_CHECK_ACTION
|
|
282
|
+
/* bitmask value used for debug message output (glibc) */
|
|
283
|
+
rb_define_const(mMall, "CHECK_ACTION", INT2FIX(M_CHECK_ACTION));
|
|
284
|
+
#endif
|
|
285
|
+
|
|
286
|
+
#ifdef M_PERTURB
|
|
287
|
+
/* perturb memory allocations with a given byte (for debugging) (glibc) */
|
|
288
|
+
rb_define_const(mMall, "PERTURB", INT2FIX(M_PERTURB));
|
|
289
|
+
#endif
|
|
290
|
+
|
|
291
|
+
#ifdef M_ARENA_TEST
|
|
292
|
+
/* initial number of arenas to allocate (glibc 2.10+) */
|
|
293
|
+
rb_define_const(mMall, "ARENA_TEST", INT2FIX(M_ARENA_TEST));
|
|
294
|
+
#endif
|
|
295
|
+
|
|
296
|
+
#ifdef M_ARENA_MAX
|
|
297
|
+
/* maximum number of arenas to allocate (glibc 2.10+) */
|
|
298
|
+
rb_define_const(mMall, "ARENA_MAX", INT2FIX(M_ARENA_MAX));
|
|
299
|
+
#endif
|
|
300
|
+
|
|
301
|
+
}
|
data/ext/mall/mall.c.erb
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
#include <malloc.h>
|
|
3
|
+
#include <stdio.h>
|
|
4
|
+
<%
|
|
5
|
+
mallinfo_keys = %w(
|
|
6
|
+
arena
|
|
7
|
+
ordblks
|
|
8
|
+
smblks
|
|
9
|
+
hblks
|
|
10
|
+
hblkhd
|
|
11
|
+
usmblks
|
|
12
|
+
fsmblks
|
|
13
|
+
uordblks
|
|
14
|
+
fordblks
|
|
15
|
+
keepcost
|
|
16
|
+
) %>
|
|
17
|
+
|
|
18
|
+
<% mallinfo_keys.each { |x| %>
|
|
19
|
+
static VALUE sym_<%= x %>;
|
|
20
|
+
<% } %>
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* call-seq:
|
|
24
|
+
* Mall.info -> hash
|
|
25
|
+
*
|
|
26
|
+
* Returns a hash with the following keys:
|
|
27
|
+
*
|
|
28
|
+
* :arena - bytes allocated via sbrk() (and not mmap())
|
|
29
|
+
* :ordblks - number of free (unused) chunks
|
|
30
|
+
* :smblks - number of fastbin blocks[1]
|
|
31
|
+
* :hblks - number of allocated mmap()-ed regions
|
|
32
|
+
* :hblkhd - bytes allocated in mmap()-ed regions
|
|
33
|
+
* :usmblks - maximum total allocated space[1]
|
|
34
|
+
* :fsmblks - space available in freed fastbin blocks[1]
|
|
35
|
+
* :uordblks - total allocated space in use
|
|
36
|
+
* :fordblks - total free space
|
|
37
|
+
* :keepcost - top-most, releasable (via malloc_trim) space
|
|
38
|
+
*
|
|
39
|
+
* All values are limited to 32-bit integers. This uses the limited
|
|
40
|
+
* mallinfo(3) function, consider using Mall.xml and parsing its output
|
|
41
|
+
* if you are using glibc (2.10+) with malloc_info(3)
|
|
42
|
+
*
|
|
43
|
+
* See also:
|
|
44
|
+
* http:// gnu.org/software/libc/manual/html_node/Statistics-of-Malloc.html
|
|
45
|
+
*
|
|
46
|
+
* [1] - this key is unused by glibc (ptmalloc2)
|
|
47
|
+
*/
|
|
48
|
+
static VALUE info(VALUE klass)
|
|
49
|
+
{
|
|
50
|
+
VALUE rv = rb_hash_new();
|
|
51
|
+
struct mallinfo stats = mallinfo(); /* whee aggregate returns :( */
|
|
52
|
+
|
|
53
|
+
#define MALLINFO_SET(KEY) \
|
|
54
|
+
rb_hash_aset(rv, sym_##KEY, INT2FIX(stats.KEY))
|
|
55
|
+
|
|
56
|
+
MALLINFO_SET(arena);
|
|
57
|
+
MALLINFO_SET(ordblks);
|
|
58
|
+
MALLINFO_SET(smblks);
|
|
59
|
+
MALLINFO_SET(hblks);
|
|
60
|
+
MALLINFO_SET(hblkhd);
|
|
61
|
+
MALLINFO_SET(usmblks);
|
|
62
|
+
MALLINFO_SET(fsmblks);
|
|
63
|
+
MALLINFO_SET(uordblks);
|
|
64
|
+
MALLINFO_SET(fordblks);
|
|
65
|
+
MALLINFO_SET(keepcost);
|
|
66
|
+
#undef MALLINFO_SET
|
|
67
|
+
return rv;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* call-seq:
|
|
72
|
+
* Mall.opt(Mall::MMAP_THRESHOLD, 128 * 1024)
|
|
73
|
+
*
|
|
74
|
+
* some malloc implementations may not like mallopt() being called after
|
|
75
|
+
* malloc has been initialized (first call to malloc()). This is not
|
|
76
|
+
* the case with glibc malloc.
|
|
77
|
+
*
|
|
78
|
+
* See also:
|
|
79
|
+
* http://gnu.org/software/libc/manual/html_node/Malloc-Tunable-Parameters.html
|
|
80
|
+
*/
|
|
81
|
+
static VALUE opt(VALUE klass, VALUE param, VALUE value)
|
|
82
|
+
{
|
|
83
|
+
int rv = mallopt(FIX2INT(param), FIX2INT(value));
|
|
84
|
+
|
|
85
|
+
return rv == 0 ? Qfalse : Qtrue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#ifdef HAVE_MALLOC_TRIM
|
|
89
|
+
/*
|
|
90
|
+
* call-seq:
|
|
91
|
+
* Mall.trim(pad) => true or false
|
|
92
|
+
*
|
|
93
|
+
* Attempt to trim off the top of the heap and release it back to
|
|
94
|
+
* the OS. +pad+ represents the amount of free space (in bytes) to
|
|
95
|
+
* leave unreleased for future allocations.
|
|
96
|
+
*
|
|
97
|
+
* Returns true if memory was released and false if not.
|
|
98
|
+
*
|
|
99
|
+
* This method is glibc-specific.
|
|
100
|
+
*/
|
|
101
|
+
static VALUE trim(VALUE klass, VALUE pad)
|
|
102
|
+
{
|
|
103
|
+
unsigned long tmp = NUM2ULONG(pad);
|
|
104
|
+
int rv = malloc_trim((size_t)tmp);
|
|
105
|
+
|
|
106
|
+
return rv == 1 ? Qtrue : Qfalse;
|
|
107
|
+
return Qfalse;
|
|
108
|
+
}
|
|
109
|
+
#endif /* HAVE_MALLOC_TRIM */
|
|
110
|
+
|
|
111
|
+
#ifdef HAVE_MALLOC_STATS
|
|
112
|
+
/*
|
|
113
|
+
* call-seq:
|
|
114
|
+
* Mall.dump_stats
|
|
115
|
+
*
|
|
116
|
+
* Dump malloc stats to STDERR
|
|
117
|
+
*
|
|
118
|
+
* This calls malloc_stats() internally, a function that is glibc-specific
|
|
119
|
+
*/
|
|
120
|
+
static VALUE dump_stats(VALUE klass)
|
|
121
|
+
{
|
|
122
|
+
fflush(stderr);
|
|
123
|
+
malloc_stats();
|
|
124
|
+
fflush(stderr);
|
|
125
|
+
return Qnil;
|
|
126
|
+
}
|
|
127
|
+
#endif /* HAVE_MALLOC_STATS */
|
|
128
|
+
|
|
129
|
+
#ifdef HAVE_MALLOC_INFO
|
|
130
|
+
static ID id_ltlt;
|
|
131
|
+
#include <errno.h>
|
|
132
|
+
static void xmlerr(FILE *fp, int err, const char *msg)
|
|
133
|
+
{
|
|
134
|
+
fclose(fp);
|
|
135
|
+
errno = err ? err : EIO; /* gotta have something */
|
|
136
|
+
rb_sys_fail(msg);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/*
|
|
140
|
+
* call-seq:
|
|
141
|
+
* Mall.xml -> XML string
|
|
142
|
+
* Mall.xml(options = 0, io = $stderr) -> io
|
|
143
|
+
*
|
|
144
|
+
* Called with no arguments, this returns an XML string suitable for
|
|
145
|
+
* parsing with your favorite XML parser.
|
|
146
|
+
*
|
|
147
|
+
* If specified, +options+ must currently be +0+, but is reserved for
|
|
148
|
+
* future expansion.
|
|
149
|
+
*
|
|
150
|
+
* The second optional argument may be any object that responds to "<<"
|
|
151
|
+
* so it may be an IO, Array, StringIO, or String object among other
|
|
152
|
+
* things.
|
|
153
|
+
*
|
|
154
|
+
* This relies on malloc_info(3) which is only in glibc 2.10+
|
|
155
|
+
*/
|
|
156
|
+
static VALUE xml(int argc, VALUE *argv, VALUE self)
|
|
157
|
+
{
|
|
158
|
+
int err;
|
|
159
|
+
long len;
|
|
160
|
+
VALUE options, out, buf;
|
|
161
|
+
int xoptions;
|
|
162
|
+
FILE *fp;
|
|
163
|
+
|
|
164
|
+
rb_scan_args(argc, argv, "02", &options, &out);
|
|
165
|
+
xoptions = NIL_P(options) ? 0 : NUM2INT(options);
|
|
166
|
+
|
|
167
|
+
fp = tmpfile();
|
|
168
|
+
if (fp == NULL)
|
|
169
|
+
rb_sys_fail("tmpfile");
|
|
170
|
+
|
|
171
|
+
err = malloc_info(xoptions, fp);
|
|
172
|
+
if (err != 0)
|
|
173
|
+
xmlerr(fp, err, "malloc_info");
|
|
174
|
+
|
|
175
|
+
len = ftell(fp);
|
|
176
|
+
if (len < 0)
|
|
177
|
+
xmlerr(fp, errno, "ftell");
|
|
178
|
+
|
|
179
|
+
rewind(fp);
|
|
180
|
+
buf = rb_str_new(0, len);
|
|
181
|
+
if (fread(RSTRING_PTR(buf), 1, len, fp) != (size_t)len)
|
|
182
|
+
xmlerr(fp, ferror(fp), "fread");
|
|
183
|
+
fclose(fp);
|
|
184
|
+
|
|
185
|
+
if (NIL_P(out))
|
|
186
|
+
return buf;
|
|
187
|
+
return rb_funcall(out, id_ltlt, 1, buf);
|
|
188
|
+
}
|
|
189
|
+
#endif /* HAVE_MALLOC_INFO */
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* Mall is a single module with several singleton methods, most of which
|
|
193
|
+
* are glibc-specific. All constants may be used as the first argument
|
|
194
|
+
* to Mall.opt.
|
|
195
|
+
*/
|
|
196
|
+
void Init_mall(void)
|
|
197
|
+
{
|
|
198
|
+
VALUE mMall = rb_define_module("Mall");
|
|
199
|
+
rb_define_singleton_method(mMall, "opt", opt, 2);
|
|
200
|
+
rb_define_singleton_method(mMall, "info", info, 0);
|
|
201
|
+
#ifdef HAVE_MALLOC_TRIM
|
|
202
|
+
rb_define_singleton_method(mMall, "trim", trim, 1);
|
|
203
|
+
#endif /* HAVE_MALLOC_TRIM */
|
|
204
|
+
#ifdef HAVE_MALLOC_STATS
|
|
205
|
+
rb_define_singleton_method(mMall, "dump_stats", dump_stats, 0);
|
|
206
|
+
#endif /* HAVE_MALLOC_STATS */
|
|
207
|
+
#ifdef HAVE_MALLOC_INFO
|
|
208
|
+
id_ltlt = rb_intern("<<");
|
|
209
|
+
rb_define_singleton_method(mMall, "xml", xml, -1);
|
|
210
|
+
#endif /* HAVE_MALLOC_INFO*/
|
|
211
|
+
|
|
212
|
+
<% mallinfo_keys.each { |x| %>
|
|
213
|
+
sym_<%= x %> = ID2SYM(rb_intern("<%= x %>"));
|
|
214
|
+
<% } %>
|
|
215
|
+
|
|
216
|
+
<%
|
|
217
|
+
{
|
|
218
|
+
:mxfast => 'max request size for "fastbins"',
|
|
219
|
+
:nlblks => 'unused in glibc',
|
|
220
|
+
:grain => 'unused in glibc',
|
|
221
|
+
:keep => 'unused in glibc',
|
|
222
|
+
:trim_threshold =>
|
|
223
|
+
'maximum amount of unused memory at the top of the heap' \
|
|
224
|
+
'to keep before releasing it back to the kernel',
|
|
225
|
+
:top_pad =>
|
|
226
|
+
'amount of extra space to allocate when allocating from the heap',
|
|
227
|
+
:mmap_threshold =>
|
|
228
|
+
'the request size threshold for using mmap() (instead of sbrk())',
|
|
229
|
+
:mmap_max =>
|
|
230
|
+
'the maximum number of active mmap() requests in use at once',
|
|
231
|
+
:check_action =>
|
|
232
|
+
'bitmask value used for debug message output (glibc)',
|
|
233
|
+
:perturb =>
|
|
234
|
+
'perturb memory allocations with a given byte (for debugging) (glibc)',
|
|
235
|
+
:arena_test => 'initial number of arenas to allocate (glibc 2.10+)',
|
|
236
|
+
:arena_max => 'maximum number of arenas to allocate (glibc 2.10+)',
|
|
237
|
+
}.each { |opt, doc|
|
|
238
|
+
opt = opt.to_s.upcase!
|
|
239
|
+
m_opt = "M_#{opt}"
|
|
240
|
+
%>
|
|
241
|
+
#ifdef <%= m_opt %>
|
|
242
|
+
/* <%= doc %> */
|
|
243
|
+
rb_define_const(mMall, "<%= opt %>", INT2FIX(<%= m_opt %>));
|
|
244
|
+
#endif
|
|
245
|
+
<% } %>
|
|
246
|
+
}
|
data/mall.gemspec
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
manifest = File.exist?('.manifest') ?
|
|
2
|
+
IO.readlines('.manifest').map!(&:chomp!) : `git ls-files`.split("\n")
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = %q{mall}
|
|
6
|
+
s.version = (ENV["VERSION"] || '1.0.3').dup
|
|
7
|
+
s.authors = ["#{s.name} hackers (mall@yhbt.net)", "Ivan Prisyazhnyy"]
|
|
8
|
+
s.description = File.read('README').split("\n\n")[1] + "\n\n" +
|
|
9
|
+
"1.0.3 fixes minor issues to be compatible with gem install and rake."
|
|
10
|
+
s.email = ["john.koepi@gmail.com", "mall@yhbt.net"]
|
|
11
|
+
s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
|
|
12
|
+
File.exist?(f)
|
|
13
|
+
end
|
|
14
|
+
s.require_paths = %w(ext)
|
|
15
|
+
s.files = manifest
|
|
16
|
+
s.homepage = 'https://github.com/sitano/mall'
|
|
17
|
+
s.summary = 'access malloc tuning/reporting functions + glibc extras. linux only.'
|
|
18
|
+
s.test_files = Dir["test/test_*.rb"]
|
|
19
|
+
s.extensions = %w(ext/mall/extconf.rb)
|
|
20
|
+
s.licenses = ["LGPL"]
|
|
21
|
+
end
|
data/pkg.mk
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
RUBY = ruby
|
|
2
|
+
RAKE = rake
|
|
3
|
+
RSYNC = rsync
|
|
4
|
+
OLDDOC = olddoc
|
|
5
|
+
RDOC = rdoc
|
|
6
|
+
|
|
7
|
+
GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
|
|
8
|
+
@./GIT-VERSION-GEN
|
|
9
|
+
-include GIT-VERSION-FILE
|
|
10
|
+
-include local.mk
|
|
11
|
+
DLEXT := $(shell $(RUBY) -rrbconfig -e 'puts RbConfig::CONFIG["DLEXT"]')
|
|
12
|
+
RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
|
|
13
|
+
RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
|
|
14
|
+
lib := lib
|
|
15
|
+
|
|
16
|
+
ext := $(firstword $(wildcard ext/*))
|
|
17
|
+
ifneq ($(ext),)
|
|
18
|
+
ext_pfx := tmp/ext/$(RUBY_ENGINE)-$(RUBY_VERSION)
|
|
19
|
+
ext_h := $(wildcard $(ext)/*/*.h $(ext)/*.h)
|
|
20
|
+
ext_src := $(wildcard $(ext)/*.c $(ext_h))
|
|
21
|
+
ext_pfx_src := $(addprefix $(ext_pfx)/,$(ext_src))
|
|
22
|
+
ext_d := $(ext_pfx)/$(ext)/.d
|
|
23
|
+
$(ext)/extconf.rb: $(wildcard $(ext)/*.h)
|
|
24
|
+
@>> $@
|
|
25
|
+
$(ext_d):
|
|
26
|
+
@mkdir -p $(@D)
|
|
27
|
+
@> $@
|
|
28
|
+
$(ext_pfx)/$(ext)/%: $(ext)/% $(ext_d)
|
|
29
|
+
install -m 644 $< $@
|
|
30
|
+
$(ext_pfx)/$(ext)/Makefile: $(ext)/extconf.rb $(ext_d) $(ext_h)
|
|
31
|
+
$(RM) -f $(@D)/*.o
|
|
32
|
+
cd $(@D) && $(RUBY) $(CURDIR)/$(ext)/extconf.rb $(EXTCONF_ARGS)
|
|
33
|
+
ext_sfx := _ext.$(DLEXT)
|
|
34
|
+
ext_dl := $(ext_pfx)/$(ext)/$(notdir $(ext)_ext.$(DLEXT))
|
|
35
|
+
$(ext_dl): $(ext_src) $(ext_pfx_src) $(ext_pfx)/$(ext)/Makefile
|
|
36
|
+
@echo $^ == $@
|
|
37
|
+
$(MAKE) -C $(@D)
|
|
38
|
+
lib := $(lib):$(ext_pfx)/$(ext)
|
|
39
|
+
build: $(ext_dl)
|
|
40
|
+
else
|
|
41
|
+
build:
|
|
42
|
+
endif
|
|
43
|
+
|
|
44
|
+
pkg_extra += GIT-VERSION-FILE NEWS LATEST
|
|
45
|
+
NEWS: GIT-VERSION-FILE .olddoc.yml
|
|
46
|
+
$(OLDDOC) prepare
|
|
47
|
+
LATEST: NEWS
|
|
48
|
+
|
|
49
|
+
manifest:
|
|
50
|
+
$(RM) .manifest
|
|
51
|
+
$(MAKE) .manifest
|
|
52
|
+
|
|
53
|
+
.manifest: $(pkg_extra)
|
|
54
|
+
(git ls-files && for i in $@ $(pkg_extra); do echo $$i; done) | \
|
|
55
|
+
LC_ALL=C sort > $@+
|
|
56
|
+
cmp $@+ $@ || mv $@+ $@
|
|
57
|
+
$(RM) $@+
|
|
58
|
+
|
|
59
|
+
doc:: .document .olddoc.yml $(pkg_extra) $(PLACEHOLDERS)
|
|
60
|
+
-find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
|
61
|
+
-find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
|
62
|
+
$(RM) -r doc
|
|
63
|
+
$(RDOC) -f dark216
|
|
64
|
+
$(OLDDOC) merge
|
|
65
|
+
install -m644 COPYING doc/COPYING
|
|
66
|
+
install -m644 NEWS doc/NEWS
|
|
67
|
+
install -m644 NEWS.atom.xml doc/NEWS.atom.xml
|
|
68
|
+
install -m644 $(shell LC_ALL=C grep '^[A-Z]' .document) doc/
|
|
69
|
+
|
|
70
|
+
ifneq ($(VERSION),)
|
|
71
|
+
pkggem := pkg/$(rfpackage)-$(VERSION).gem
|
|
72
|
+
pkgtgz := pkg/$(rfpackage)-$(VERSION).tgz
|
|
73
|
+
|
|
74
|
+
# ensures we're actually on the tagged $(VERSION), only used for release
|
|
75
|
+
verify:
|
|
76
|
+
test x"$(shell umask)" = x0022
|
|
77
|
+
git rev-parse --verify refs/tags/v$(VERSION)^{}
|
|
78
|
+
git diff-index --quiet HEAD^0
|
|
79
|
+
test $$(git rev-parse --verify HEAD^0) = \
|
|
80
|
+
$$(git rev-parse --verify refs/tags/v$(VERSION)^{})
|
|
81
|
+
|
|
82
|
+
fix-perms:
|
|
83
|
+
-git ls-tree -r HEAD | awk '/^100644 / {print $$NF}' | xargs chmod 644
|
|
84
|
+
-git ls-tree -r HEAD | awk '/^100755 / {print $$NF}' | xargs chmod 755
|
|
85
|
+
|
|
86
|
+
gem: $(pkggem)
|
|
87
|
+
|
|
88
|
+
install-gem: $(pkggem)
|
|
89
|
+
gem install --local $(CURDIR)/$<
|
|
90
|
+
|
|
91
|
+
$(pkggem): manifest fix-perms
|
|
92
|
+
gem build $(rfpackage).gemspec
|
|
93
|
+
mkdir -p pkg
|
|
94
|
+
mv $(@F) $@
|
|
95
|
+
|
|
96
|
+
$(pkgtgz): distdir = $(basename $@)
|
|
97
|
+
$(pkgtgz): HEAD = v$(VERSION)
|
|
98
|
+
$(pkgtgz): manifest fix-perms
|
|
99
|
+
@test -n "$(distdir)"
|
|
100
|
+
$(RM) -r $(distdir)
|
|
101
|
+
mkdir -p $(distdir)
|
|
102
|
+
tar cf - $$(cat .manifest) | (cd $(distdir) && tar xf -)
|
|
103
|
+
cd pkg && tar cf - $(basename $(@F)) | gzip -9 > $(@F)+
|
|
104
|
+
mv $@+ $@
|
|
105
|
+
|
|
106
|
+
package: $(pkgtgz) $(pkggem)
|
|
107
|
+
|
|
108
|
+
release:: verify package
|
|
109
|
+
# push gem to RubyGems.org
|
|
110
|
+
gem push $(pkggem)
|
|
111
|
+
else
|
|
112
|
+
gem install-gem: GIT-VERSION-FILE
|
|
113
|
+
$(MAKE) $@ VERSION=$(GIT_VERSION)
|
|
114
|
+
endif
|
|
115
|
+
|
|
116
|
+
all:: check
|
|
117
|
+
test_units := $(wildcard test/test_*.rb)
|
|
118
|
+
test: check
|
|
119
|
+
check: test-unit
|
|
120
|
+
test-unit: $(test_units)
|
|
121
|
+
$(test_units): build
|
|
122
|
+
$(VALGRIND) $(RUBY) -w -I $(lib) $@ $(RUBY_TEST_OPTS)
|
|
123
|
+
|
|
124
|
+
# this requires GNU coreutils variants
|
|
125
|
+
ifneq ($(RSYNC_DEST),)
|
|
126
|
+
publish_doc:
|
|
127
|
+
-git set-file-times
|
|
128
|
+
$(MAKE) doc
|
|
129
|
+
$(MAKE) doc_gz
|
|
130
|
+
$(RSYNC) -av doc/ $(RSYNC_DEST)/
|
|
131
|
+
git ls-files | xargs touch
|
|
132
|
+
endif
|
|
133
|
+
|
|
134
|
+
# Create gzip variants of the same timestamp as the original so nginx
|
|
135
|
+
# "gzip_static on" can serve the gzipped versions directly.
|
|
136
|
+
doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.gz$$')
|
|
137
|
+
doc_gz:
|
|
138
|
+
for i in $(docs); do \
|
|
139
|
+
gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
|
|
140
|
+
check-warnings:
|
|
141
|
+
@(for i in $$(git ls-files '*.rb'| grep -v '^setup\.rb$$'); \
|
|
142
|
+
do $(RUBY) -d -W2 -c $$i; done) | grep -v '^Syntax OK$$' || :
|
|
143
|
+
|
|
144
|
+
ifneq ($(PLACEHOLDERS),)
|
|
145
|
+
$(PLACEHOLDERS):
|
|
146
|
+
echo olddoc_placeholder > $@
|
|
147
|
+
endif
|
|
148
|
+
|
|
149
|
+
.PHONY: all .FORCE-GIT-VERSION-FILE doc check test $(test_units) manifest
|
|
150
|
+
.PHONY: check-warnings
|