mwrap 2.1.0 → 2.3.0
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 +4 -4
- data/.document +1 -0
- data/.gitignore +3 -0
- data/.olddoc.yml +3 -1
- data/MANIFEST +3 -0
- data/README +8 -6
- data/Rakefile +29 -1
- data/VERSION-GEN +36 -0
- data/bin/mwrap +20 -1
- data/ext/mwrap/extconf.rb +12 -5
- data/ext/mwrap/mwrap.c +100 -70
- data/lib/mwrap/.gitignore +1 -0
- data/lib/mwrap/version.rb +1 -0
- data/lib/mwrap_rack.rb +3 -5
- data/mwrap.gemspec +7 -4
- data/test/test_mwrap.rb +19 -12
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b967676ac9ff95d0771147fc464a06ce6a88c9a7e07c3eef97b0cf0a273ff822
|
4
|
+
data.tar.gz: f99e5f3a27adecf190e11a921a58f46c9514e28a88d83602c2421dbd8cecc90b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f3a089d3bf14258b0382d13f8d4428ffd0291d6e9af8fa33331696e5b55e5a279f0dafc30fb1018e73a199d9d3b8cbe826dd814dfd80941ae059581fa6f330c
|
7
|
+
data.tar.gz: 54a2bc06918d050e161ff0c9457ca67ebc3573a5795495d5ab57637d0bb37830e442f3073cede28d672938baaba7e7057b9d0fa8f40c64b85864add6e81e53d0
|
data/.document
CHANGED
data/.gitignore
CHANGED
data/.olddoc.yml
CHANGED
@@ -5,4 +5,6 @@ rdoc_url: https://80x24.org/mwrap/
|
|
5
5
|
ml_url: https://80x24.org/mwrap-public/
|
6
6
|
public_email: mwrap-public@80x24.org
|
7
7
|
nntp_url:
|
8
|
-
|
8
|
+
- nntps://news.public-inbox.org/inbox.comp.lang.ruby.mwrap
|
9
|
+
imap_url:
|
10
|
+
- imaps://;AUTH=ANONYMOUS@80x24.org/inbox.comp.lang.ruby.mwrap.0
|
data/MANIFEST
CHANGED
data/README
CHANGED
@@ -23,7 +23,7 @@ It does not require recompiling or rebuilding Ruby, but only
|
|
23
23
|
supports Ruby trunk (2.6.0dev+) on a few platforms:
|
24
24
|
|
25
25
|
* GNU/Linux
|
26
|
-
* FreeBSD (tested 11.1)
|
26
|
+
* FreeBSD (tested 11.1 on Ruby 2.6, currently broken with Ruby 3.x)
|
27
27
|
|
28
28
|
It may work on NetBSD, OpenBSD and DragonFly BSD.
|
29
29
|
|
@@ -67,16 +67,18 @@ first two columns to find the hottest malloc locations.
|
|
67
67
|
mwrap 2.0.0+ also supports a Rack application endpoint,
|
68
68
|
it is documented at:
|
69
69
|
|
70
|
-
|
70
|
+
https://80x24.org/mwrap/MwrapRack.html
|
71
71
|
|
72
72
|
== Known problems
|
73
73
|
|
74
74
|
* 32-bit machines are prone to overflow (WONTFIX)
|
75
75
|
|
76
|
-
==
|
76
|
+
== Public mail archives and contact info:
|
77
77
|
|
78
|
-
|
79
|
-
|
78
|
+
* https://80x24.org/mwrap-public/
|
79
|
+
* nntps://80x24.org/inbox.comp.lang.ruby.mwrap
|
80
|
+
* imaps://;AUTH=ANONYMOUS@80x24.org/inbox.comp.lang.ruby.mwrap.0
|
81
|
+
* https://80x24.org/mwrap-public/_/text/help/#pop3
|
80
82
|
|
81
83
|
No subscription will ever be required to post, but HTML mail
|
82
84
|
will be rejected:
|
@@ -88,7 +90,7 @@ will be rejected:
|
|
88
90
|
git clone https://80x24.org/mwrap.git
|
89
91
|
|
90
92
|
Send all patches and pull requests (use "git request-pull" to format) to
|
91
|
-
|
93
|
+
mwrap-public@80x24.org. We do not use centralized or proprietary messaging
|
92
94
|
systems.
|
93
95
|
|
94
96
|
== License
|
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) mwrap hackers <mwrap-public@80x24.org>
|
2
2
|
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
3
3
|
require 'rake/testtask'
|
4
4
|
begin
|
@@ -14,3 +14,31 @@ task :default => :compile
|
|
14
14
|
|
15
15
|
c_files = File.readlines('MANIFEST').grep(%r{ext/.*\.[ch]$}).map!(&:chomp!)
|
16
16
|
task 'compile:mwrap' => c_files
|
17
|
+
|
18
|
+
olddoc = ENV['OLDDOC'] || 'olddoc'
|
19
|
+
rdoc = ENV['RDOC'] || 'rdoc'
|
20
|
+
task :rsync_docs do
|
21
|
+
require 'fileutils'
|
22
|
+
top = %w(README COPYING LATEST NEWS NEWS.atom.xml)
|
23
|
+
system("git", "set-file-times")
|
24
|
+
dest = ENV["RSYNC_DEST"] || "80x24.org:/srv/80x24/mwrap/"
|
25
|
+
FileUtils.rm_rf('doc')
|
26
|
+
sh "#{olddoc} prepare"
|
27
|
+
sh "#{rdoc} -f dark216" # dark216 requires olddoc 1.7+
|
28
|
+
File.unlink('doc/created.rid') rescue nil
|
29
|
+
File.unlink('doc/index.html') rescue nil
|
30
|
+
FileUtils.cp(top, 'doc')
|
31
|
+
sh "#{olddoc} merge"
|
32
|
+
|
33
|
+
Dir['doc/**/*'].each do |txt|
|
34
|
+
st = File.stat(txt)
|
35
|
+
if st.file?
|
36
|
+
gz = "#{txt}.gz"
|
37
|
+
tmp = "#{gz}.#$$"
|
38
|
+
sh("gzip --rsyncable -9 <#{txt} >#{tmp}")
|
39
|
+
File.utime(st.atime, st.mtime, tmp) # make nginx gzip_static happy
|
40
|
+
File.rename(tmp, gz)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
sh("rsync --chmod=Fugo=r #{ENV['RSYNC_OPT']} -av doc/ #{dest}/")
|
44
|
+
end
|
data/VERSION-GEN
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
VF=lib/mwrap/version.rb
|
3
|
+
DEF_VER=v2.3.0
|
4
|
+
VN=$(git describe HEAD 2>/dev/null)
|
5
|
+
if test $? -eq 0
|
6
|
+
then
|
7
|
+
case "$VN" in
|
8
|
+
v[0-9]*)
|
9
|
+
set -e
|
10
|
+
git update-index -q --refresh
|
11
|
+
set +e
|
12
|
+
git diff-index --quiet HEAD -- || VN="$VN-dirty"
|
13
|
+
set -e
|
14
|
+
VN=$(echo $VN | tr '-' '.')
|
15
|
+
;;
|
16
|
+
esac
|
17
|
+
fi
|
18
|
+
set -e
|
19
|
+
|
20
|
+
case $VN in
|
21
|
+
'') VN="$DEF_VER" ;;
|
22
|
+
esac
|
23
|
+
|
24
|
+
VN=$(expr "$VN" : v*'\(.*\)')
|
25
|
+
VC=unset
|
26
|
+
if test -r $VF
|
27
|
+
then
|
28
|
+
VC="$(cat $VF)"
|
29
|
+
fi
|
30
|
+
|
31
|
+
new="module Mwrap; VERSION = '$VN'.freeze; end"
|
32
|
+
if test x"$new" != x"$VC"
|
33
|
+
then
|
34
|
+
echo "$new" >$VF
|
35
|
+
fi
|
36
|
+
echo $VN
|
data/bin/mwrap
CHANGED
@@ -1,7 +1,26 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
# frozen_string_literal: true
|
3
|
-
# Copyright (C)
|
3
|
+
# Copyright (C) mwrap hackers <mwrap-public@80x24.org>
|
4
4
|
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
5
|
+
help = <<EOM
|
6
|
+
usage: mwrap COMMAND [ARGS]
|
7
|
+
see https://80x24.org/mwrap/README.html for more info
|
8
|
+
EOM
|
9
|
+
ARGV.empty? and abort help
|
10
|
+
ARGV.each do |x|
|
11
|
+
case x
|
12
|
+
when '--version', '-v'
|
13
|
+
require 'mwrap/version'
|
14
|
+
puts "mwrap #{Mwrap::VERSION} - #{RUBY_DESCRIPTION}"
|
15
|
+
exit 0
|
16
|
+
when '--help', '-h'
|
17
|
+
puts help
|
18
|
+
exit 0
|
19
|
+
else # don't intercept --version/--help intended for commands we wrap
|
20
|
+
break
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
5
24
|
require 'mwrap'
|
6
25
|
mwrap_so = $".grep(%r{/mwrap\.so\z})[0] or abort "mwrap.so not loaded"
|
7
26
|
cur = ENV['LD_PRELOAD']
|
data/ext/mwrap/extconf.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# Copyright (C)
|
2
|
+
# Copyright (C) mwrap hackers <mwrap-public@80x24.org>
|
3
3
|
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
4
4
|
require 'mkmf'
|
5
5
|
|
@@ -11,18 +11,25 @@ have_library 'dl'
|
|
11
11
|
have_library 'c'
|
12
12
|
have_library 'execinfo' # FreeBSD
|
13
13
|
|
14
|
-
if try_link(<<
|
14
|
+
if try_link(<<EOC)
|
15
15
|
int main(void) { return __builtin_add_overflow_p(0,0,(int)1); }
|
16
|
-
|
16
|
+
EOC
|
17
17
|
$defs << '-DHAVE_BUILTIN_ADD_OVERFLOW_P'
|
18
18
|
end
|
19
19
|
|
20
|
-
if try_link(<<
|
20
|
+
if try_link(<<EOC)
|
21
21
|
int main(int a) { return __builtin_add_overflow(0,0,&a); }
|
22
|
-
|
22
|
+
EOC
|
23
23
|
$defs << '-DHAVE_BUILTIN_ADD_OVERFLOW_P'
|
24
24
|
else
|
25
25
|
abort 'missing __builtin_add_overflow'
|
26
26
|
end
|
27
27
|
|
28
|
+
begin
|
29
|
+
if n = GC::INTERNAL_CONSTANTS[:HEAP_PAGE_SIZE]
|
30
|
+
$defs << "-DHEAP_PAGE_SIZE=#{n}"
|
31
|
+
end
|
32
|
+
rescue NameError
|
33
|
+
end
|
34
|
+
|
28
35
|
create_makefile 'mwrap'
|
data/ext/mwrap/mwrap.c
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (C)
|
2
|
+
* Copyright (C) mwrap hackers <mwrap-public@80x24.org>
|
3
3
|
* License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
4
4
|
*/
|
5
5
|
#define _LGPL_SOURCE /* allows URCU to inline some stuff */
|
6
|
-
#include <ruby
|
6
|
+
#include <ruby.h> /* defines HAVE_RUBY_RACTOR_H on 3.0+ */
|
7
7
|
#include <ruby/thread.h>
|
8
8
|
#include <ruby/io.h>
|
9
9
|
#include <execinfo.h>
|
@@ -22,15 +22,29 @@
|
|
22
22
|
#include <urcu/rculist.h>
|
23
23
|
#include "jhash.h"
|
24
24
|
|
25
|
+
#if __STDC_VERSION__ >= 201112
|
26
|
+
# define MWRAP_TSD _Thread_local
|
27
|
+
#elif defined(__GNUC__)
|
28
|
+
# define MWRAP_TSD __thread
|
29
|
+
#else
|
30
|
+
# error _Thread_local nor __thread supported
|
31
|
+
#endif
|
32
|
+
|
25
33
|
static ID id_uminus;
|
26
34
|
const char *rb_source_location_cstr(int *line); /* requires 2.6.0dev */
|
27
|
-
|
35
|
+
|
36
|
+
#ifdef HAVE_RUBY_RACTOR_H /* Ruby 3.0+ */
|
37
|
+
extern MWRAP_TSD void * __attribute__((weak)) ruby_current_ec;
|
38
|
+
#else /* Ruby 2.6-2.7 */
|
28
39
|
extern void * __attribute__((weak)) ruby_current_execution_context_ptr;
|
40
|
+
# define ruby_current_ec ruby_current_execution_context_ptr
|
41
|
+
#endif
|
29
42
|
extern void * __attribute__((weak)) ruby_current_vm_ptr; /* for rb_gc_count */
|
30
43
|
extern size_t __attribute__((weak)) rb_gc_count(void);
|
31
44
|
extern VALUE __attribute__((weak)) rb_cObject;
|
32
45
|
extern VALUE __attribute__((weak)) rb_eTypeError;
|
33
46
|
extern VALUE __attribute__((weak)) rb_yield(VALUE);
|
47
|
+
int __attribute__((weak)) ruby_thread_has_gvl_p(void);
|
34
48
|
|
35
49
|
static size_t total_bytes_inc, total_bytes_dec;
|
36
50
|
|
@@ -40,18 +54,16 @@ static size_t total_bytes_inc, total_bytes_dec;
|
|
40
54
|
/* match values in Ruby gc.c */
|
41
55
|
#define HEAP_PAGE_ALIGN_LOG 14
|
42
56
|
enum {
|
43
|
-
HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG)
|
57
|
+
HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG)
|
58
|
+
#ifndef HEAP_PAGE_SIZE /* Ruby 2.6-2.7 only */
|
59
|
+
,
|
44
60
|
REQUIRED_SIZE_BY_MALLOC = (sizeof(size_t) * 5),
|
45
61
|
HEAP_PAGE_SIZE = (HEAP_PAGE_ALIGN - REQUIRED_SIZE_BY_MALLOC)
|
62
|
+
#endif
|
46
63
|
};
|
47
64
|
|
48
65
|
#define IS_HEAP_PAGE_BODY ((struct src_loc *)-1)
|
49
66
|
|
50
|
-
int __attribute__((weak)) ruby_thread_has_gvl_p(void)
|
51
|
-
{
|
52
|
-
return 0;
|
53
|
-
}
|
54
|
-
|
55
67
|
#ifdef __FreeBSD__
|
56
68
|
void *__malloc(size_t);
|
57
69
|
void __free(void *);
|
@@ -75,7 +87,7 @@ static int resolving_malloc;
|
|
75
87
|
} \
|
76
88
|
} while (0)
|
77
89
|
|
78
|
-
static
|
90
|
+
static MWRAP_TSD size_t locating;
|
79
91
|
static size_t generation;
|
80
92
|
static size_t page_size;
|
81
93
|
static struct cds_lfht *totals;
|
@@ -87,9 +99,43 @@ union padded_mutex {
|
|
87
99
|
/* a round-robin pool of mutexes */
|
88
100
|
#define MUTEX_NR (1 << 6)
|
89
101
|
#define MUTEX_MASK (MUTEX_NR - 1)
|
102
|
+
#ifdef __FreeBSD__
|
103
|
+
# define STATIC_MTX_INIT_OK (0)
|
104
|
+
#else /* only tested on Linux + glibc */
|
105
|
+
# define STATIC_MTX_INIT_OK (1)
|
106
|
+
#endif
|
90
107
|
static size_t mutex_i;
|
91
108
|
static union padded_mutex mutexes[MUTEX_NR] = {
|
109
|
+
#if STATIC_MTX_INIT_OK
|
92
110
|
[0 ... (MUTEX_NR-1)].mtx = PTHREAD_MUTEX_INITIALIZER
|
111
|
+
#endif
|
112
|
+
};
|
113
|
+
|
114
|
+
#define ACC_INIT(name) { .nr=0, .min=INT64_MAX, .max=-1, .m2=0, .mean=0 }
|
115
|
+
struct acc {
|
116
|
+
uint64_t nr;
|
117
|
+
int64_t min;
|
118
|
+
int64_t max;
|
119
|
+
double m2;
|
120
|
+
double mean;
|
121
|
+
};
|
122
|
+
|
123
|
+
/* for tracking 16K-aligned heap page bodies (protected by GVL) */
|
124
|
+
struct {
|
125
|
+
pthread_mutex_t lock;
|
126
|
+
struct cds_list_head bodies;
|
127
|
+
struct cds_list_head freed;
|
128
|
+
|
129
|
+
struct acc alive;
|
130
|
+
struct acc reborn;
|
131
|
+
} hpb_stats = {
|
132
|
+
#if STATIC_MTX_INIT_OK
|
133
|
+
.lock = PTHREAD_MUTEX_INITIALIZER,
|
134
|
+
#endif
|
135
|
+
.bodies = CDS_LIST_HEAD_INIT(hpb_stats.bodies),
|
136
|
+
.freed = CDS_LIST_HEAD_INIT(hpb_stats.freed),
|
137
|
+
.alive = ACC_INIT(hpb_stats.alive),
|
138
|
+
.reborn = ACC_INIT(hpb_stats.reborn)
|
93
139
|
};
|
94
140
|
|
95
141
|
static pthread_mutex_t *mutex_assign(void)
|
@@ -108,12 +154,11 @@ __attribute__((constructor)) static void resolve_malloc(void)
|
|
108
154
|
int err;
|
109
155
|
++locating;
|
110
156
|
|
111
|
-
#ifdef __FreeBSD__
|
112
157
|
/*
|
113
158
|
* PTHREAD_MUTEX_INITIALIZER on FreeBSD means lazy initialization,
|
114
159
|
* which happens at pthread_mutex_lock, and that calls calloc
|
115
160
|
*/
|
116
|
-
{
|
161
|
+
if (!STATIC_MTX_INIT_OK) {
|
117
162
|
size_t i;
|
118
163
|
|
119
164
|
for (i = 0; i < MUTEX_NR; i++) {
|
@@ -123,24 +168,30 @@ __attribute__((constructor)) static void resolve_malloc(void)
|
|
123
168
|
_exit(1);
|
124
169
|
}
|
125
170
|
}
|
171
|
+
err = pthread_mutex_init(&hpb_stats.lock, 0);
|
172
|
+
if (err) {
|
173
|
+
fprintf(stderr, "error: %s\n", strerror(err));
|
174
|
+
_exit(1);
|
175
|
+
}
|
126
176
|
/* initialize mutexes used by urcu-bp */
|
127
177
|
rcu_read_lock();
|
128
178
|
rcu_read_unlock();
|
179
|
+
#ifndef __FreeBSD__
|
180
|
+
} else {
|
181
|
+
if (!real_malloc) {
|
182
|
+
resolving_malloc = 1;
|
183
|
+
real_malloc = dlsym(RTLD_NEXT, "malloc");
|
184
|
+
}
|
185
|
+
real_free = dlsym(RTLD_NEXT, "free");
|
186
|
+
if (!real_malloc || !real_free) {
|
187
|
+
fprintf(stderr, "missing malloc/aligned_alloc/free\n"
|
188
|
+
"\t%p %p\n", real_malloc, real_free);
|
189
|
+
_exit(1);
|
190
|
+
}
|
191
|
+
#endif /* !__FreeBSD__ */
|
129
192
|
}
|
130
|
-
|
131
|
-
if (!
|
132
|
-
resolving_malloc = 1;
|
133
|
-
real_malloc = dlsym(RTLD_NEXT, "malloc");
|
134
|
-
}
|
135
|
-
real_free = dlsym(RTLD_NEXT, "free");
|
136
|
-
if (!real_malloc || !real_free) {
|
137
|
-
fprintf(stderr, "missing malloc/aligned_alloc/free\n"
|
138
|
-
"\t%p %p\n", real_malloc, real_free);
|
139
|
-
_exit(1);
|
140
|
-
}
|
141
|
-
#endif /* !FreeBSD */
|
142
|
-
totals = lfht_new();
|
143
|
-
if (!totals)
|
193
|
+
CMM_STORE_SHARED(totals, lfht_new());
|
194
|
+
if (!CMM_LOAD_SHARED(totals))
|
144
195
|
fprintf(stderr, "failed to allocate totals table\n");
|
145
196
|
|
146
197
|
err = pthread_atfork(call_rcu_before_fork,
|
@@ -152,11 +203,18 @@ __attribute__((constructor)) static void resolve_malloc(void)
|
|
152
203
|
--locating;
|
153
204
|
}
|
154
205
|
|
206
|
+
#ifdef NDEBUG
|
207
|
+
#define QUIET_CC_WARNING(var) (void)var;
|
208
|
+
#else
|
209
|
+
#define QUIET_CC_WARNING(var)
|
210
|
+
#endif
|
211
|
+
|
155
212
|
static void
|
156
213
|
mutex_lock(pthread_mutex_t *m)
|
157
214
|
{
|
158
215
|
int err = pthread_mutex_lock(m);
|
159
216
|
assert(err == 0);
|
217
|
+
QUIET_CC_WARNING(err)
|
160
218
|
}
|
161
219
|
|
162
220
|
static void
|
@@ -164,6 +222,7 @@ mutex_unlock(pthread_mutex_t *m)
|
|
164
222
|
{
|
165
223
|
int err = pthread_mutex_unlock(m);
|
166
224
|
assert(err == 0);
|
225
|
+
QUIET_CC_WARNING(err)
|
167
226
|
}
|
168
227
|
|
169
228
|
#ifndef HAVE_MEMPCPY
|
@@ -213,36 +272,10 @@ static char *int2str(int num, char *dst, size_t * size)
|
|
213
272
|
*/
|
214
273
|
static int has_ec_p(void)
|
215
274
|
{
|
216
|
-
return
|
217
|
-
|
275
|
+
return ruby_thread_has_gvl_p && ruby_thread_has_gvl_p() &&
|
276
|
+
ruby_current_vm_ptr && ruby_current_ec;
|
218
277
|
}
|
219
278
|
|
220
|
-
struct acc {
|
221
|
-
uint64_t nr;
|
222
|
-
int64_t min;
|
223
|
-
int64_t max;
|
224
|
-
double m2;
|
225
|
-
double mean;
|
226
|
-
};
|
227
|
-
|
228
|
-
#define ACC_INIT(name) { .nr=0, .min=INT64_MAX, .max=-1, .m2=0, .mean=0 }
|
229
|
-
|
230
|
-
/* for tracking 16K-aligned heap page bodies (protected by GVL) */
|
231
|
-
struct {
|
232
|
-
pthread_mutex_t lock;
|
233
|
-
struct cds_list_head bodies;
|
234
|
-
struct cds_list_head freed;
|
235
|
-
|
236
|
-
struct acc alive;
|
237
|
-
struct acc reborn;
|
238
|
-
} hpb_stats = {
|
239
|
-
.lock = PTHREAD_MUTEX_INITIALIZER,
|
240
|
-
.bodies = CDS_LIST_HEAD_INIT(hpb_stats.bodies),
|
241
|
-
.freed = CDS_LIST_HEAD_INIT(hpb_stats.freed),
|
242
|
-
.alive = ACC_INIT(hpb_stats.alive),
|
243
|
-
.reborn = ACC_INIT(hpb_stats.reborn)
|
244
|
-
};
|
245
|
-
|
246
279
|
/* allocated via real_malloc/real_free */
|
247
280
|
struct src_loc {
|
248
281
|
pthread_mutex_t *mtx;
|
@@ -367,7 +400,7 @@ acc_stddev(const struct acc *acc)
|
|
367
400
|
return DBL2NUM(acc_stddev_dbl(acc));
|
368
401
|
}
|
369
402
|
|
370
|
-
static struct src_loc *totals_add_rcu(struct src_loc *k)
|
403
|
+
static struct src_loc *totals_add_rcu(const struct src_loc *k)
|
371
404
|
{
|
372
405
|
struct cds_lfht_iter iter;
|
373
406
|
struct cds_lfht_node *cur;
|
@@ -375,7 +408,7 @@ static struct src_loc *totals_add_rcu(struct src_loc *k)
|
|
375
408
|
struct cds_lfht *t;
|
376
409
|
|
377
410
|
again:
|
378
|
-
t =
|
411
|
+
t = CMM_LOAD_SHARED(totals);
|
379
412
|
if (!t) goto out_unlock;
|
380
413
|
cds_lfht_lookup(t, k->hval, loc_eq, k, &iter);
|
381
414
|
cur = cds_lfht_iter_get_node(&iter);
|
@@ -417,7 +450,7 @@ static struct src_loc *update_stats_rcu_lock(size_t size, uintptr_t caller)
|
|
417
450
|
static const size_t xlen = sizeof(caller);
|
418
451
|
char *dst;
|
419
452
|
|
420
|
-
if (caa_unlikely(!totals)) return 0;
|
453
|
+
if (caa_unlikely(!CMM_LOAD_SHARED(totals))) return 0;
|
421
454
|
if (locating++) goto out; /* do not recurse into another *alloc */
|
422
455
|
|
423
456
|
uatomic_add(&total_bytes_inc, size);
|
@@ -632,9 +665,9 @@ internal_memalign(void **pp, size_t alignment, size_t size, uintptr_t caller)
|
|
632
665
|
p = ptr_align(p, alignment);
|
633
666
|
h = ptr2hdr(p);
|
634
667
|
alloc_insert_rcu(l, h, size, real);
|
635
|
-
update_stats_rcu_unlock(l);
|
636
668
|
*pp = p;
|
637
669
|
}
|
670
|
+
update_stats_rcu_unlock(l);
|
638
671
|
}
|
639
672
|
|
640
673
|
return real ? 0 : ENOMEM;
|
@@ -643,16 +676,14 @@ internal_memalign(void **pp, size_t alignment, size_t size, uintptr_t caller)
|
|
643
676
|
static void *
|
644
677
|
memalign_result(int err, void *p)
|
645
678
|
{
|
646
|
-
if (caa_unlikely(err))
|
679
|
+
if (caa_unlikely(err))
|
647
680
|
errno = err;
|
648
|
-
return 0;
|
649
|
-
}
|
650
681
|
return p;
|
651
682
|
}
|
652
683
|
|
653
684
|
void *memalign(size_t alignment, size_t size)
|
654
685
|
{
|
655
|
-
void *p;
|
686
|
+
void *p = NULL;
|
656
687
|
int err = internal_memalign(&p, alignment, size, RETURN_ADDRESS(0));
|
657
688
|
return memalign_result(err, p);
|
658
689
|
}
|
@@ -667,7 +698,7 @@ void cfree(void *) __attribute__((alias("free")));
|
|
667
698
|
|
668
699
|
void *valloc(size_t size)
|
669
700
|
{
|
670
|
-
void *p;
|
701
|
+
void *p = NULL;
|
671
702
|
int err = internal_memalign(&p, page_size, size, RETURN_ADDRESS(0));
|
672
703
|
return memalign_result(err, p);
|
673
704
|
}
|
@@ -685,7 +716,7 @@ void *valloc(size_t size)
|
|
685
716
|
void *pvalloc(size_t size)
|
686
717
|
{
|
687
718
|
size_t alignment = page_size;
|
688
|
-
void *p;
|
719
|
+
void *p = NULL;
|
689
720
|
int err;
|
690
721
|
|
691
722
|
if (add_overflow_p(size, alignment)) {
|
@@ -808,7 +839,7 @@ static void *dump_to_file(void *x)
|
|
808
839
|
|
809
840
|
++locating;
|
810
841
|
rcu_read_lock();
|
811
|
-
t =
|
842
|
+
t = CMM_LOAD_SHARED(totals);
|
812
843
|
if (!t)
|
813
844
|
goto out_unlock;
|
814
845
|
cds_lfht_for_each_entry(t, &iter, l, hnode) {
|
@@ -877,7 +908,7 @@ static void *totals_reset(void *ign)
|
|
877
908
|
uatomic_set(&total_bytes_dec, 0);
|
878
909
|
|
879
910
|
rcu_read_lock();
|
880
|
-
t =
|
911
|
+
t = CMM_LOAD_SHARED(totals);
|
881
912
|
cds_lfht_for_each_entry(t, &iter, l, hnode) {
|
882
913
|
uatomic_set(&l->total, 0);
|
883
914
|
uatomic_set(&l->allocations, 0);
|
@@ -945,7 +976,7 @@ static VALUE dump_each_rcu(VALUE x)
|
|
945
976
|
struct cds_lfht_iter iter;
|
946
977
|
struct src_loc *l;
|
947
978
|
|
948
|
-
t =
|
979
|
+
t = CMM_LOAD_SHARED(totals);
|
949
980
|
cds_lfht_for_each_entry(t, &iter, l, hnode) {
|
950
981
|
VALUE v[6];
|
951
982
|
if (l->total <= a->min) continue;
|
@@ -1049,9 +1080,9 @@ static VALUE mwrap_aref(VALUE mod, VALUE loc)
|
|
1049
1080
|
|
1050
1081
|
if (!k) return val;
|
1051
1082
|
|
1083
|
+
t = CMM_LOAD_SHARED(totals);
|
1084
|
+
if (!t) return val;
|
1052
1085
|
rcu_read_lock();
|
1053
|
-
t = rcu_dereference(totals);
|
1054
|
-
if (!t) goto out_unlock;
|
1055
1086
|
|
1056
1087
|
cds_lfht_lookup(t, k->hval, loc_eq, k, &iter);
|
1057
1088
|
cur = cds_lfht_iter_get_node(&iter);
|
@@ -1059,7 +1090,6 @@ static VALUE mwrap_aref(VALUE mod, VALUE loc)
|
|
1059
1090
|
l = caa_container_of(cur, struct src_loc, hnode);
|
1060
1091
|
val = TypedData_Wrap_Struct(cSrcLoc, &src_loc_type, l);
|
1061
1092
|
}
|
1062
|
-
out_unlock:
|
1063
1093
|
rcu_read_unlock();
|
1064
1094
|
return val;
|
1065
1095
|
}
|
@@ -0,0 +1 @@
|
|
1
|
+
version.rb
|
@@ -0,0 +1 @@
|
|
1
|
+
module Mwrap; VERSION = '2.3.0'.freeze; end
|
data/lib/mwrap_rack.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C)
|
1
|
+
# Copyright (C) all contributors <mwrap-public@80x24.org>
|
2
2
|
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
3
3
|
# frozen_string_literal: true
|
4
4
|
require 'mwrap'
|
@@ -17,9 +17,6 @@ require 'cgi'
|
|
17
17
|
# map('/MWRAP') { run(MwrapRack.new) }
|
18
18
|
# map('/') { run(your_normal_app) }
|
19
19
|
#
|
20
|
-
# A live demo is available at https://80x24.org/MWRAP/
|
21
|
-
# (warning the demo machine is 32-bit, so counters will overflow)
|
22
|
-
#
|
23
20
|
# This module is only available in mwrap 2.0.0+
|
24
21
|
class MwrapRack
|
25
22
|
module HtmlResponse # :nodoc:
|
@@ -115,10 +112,11 @@ class MwrapRack
|
|
115
112
|
end
|
116
113
|
|
117
114
|
GC_STAT_URL = 'https://docs.ruby-lang.org/en/trunk/GC.html#method-c-stat'
|
118
|
-
GC_STAT_HELP = <<~
|
115
|
+
GC_STAT_HELP = <<~EOM
|
119
116
|
<p>Non-Infinity lifespans can indicate fragmentation.
|
120
117
|
<p>See <a
|
121
118
|
href="#{GC_STAT_URL}">#{GC_STAT_URL}</a> for info on GC.stat values.
|
119
|
+
EOM
|
122
120
|
|
123
121
|
def each
|
124
122
|
Mwrap.quiet do
|
data/mwrap.gemspec
CHANGED
@@ -1,20 +1,23 @@
|
|
1
1
|
git_manifest = `git ls-files 2>/dev/null`.split("\n")
|
2
|
+
git_ok = $?.success?
|
3
|
+
git_manifest << 'lib/mwrap/version.rb'.freeze # generated by ./VERSION-GEN
|
2
4
|
manifest = File.exist?('MANIFEST') ?
|
3
5
|
File.readlines('MANIFEST').map!(&:chomp).delete_if(&:empty?) : git_manifest
|
4
|
-
if
|
6
|
+
if git_ok && manifest != git_manifest
|
5
7
|
tmp = "MANIFEST.#$$.tmp"
|
6
8
|
File.open(tmp, 'w') { |fp| fp.puts(git_manifest.join("\n")) }
|
7
9
|
File.rename(tmp, 'MANIFEST')
|
8
10
|
system('git add MANIFEST')
|
9
11
|
end
|
10
12
|
|
11
|
-
|
13
|
+
version = `./VERSION-GEN`.chomp
|
14
|
+
$?.success? or abort './VERSION-GEN failed'
|
12
15
|
|
13
16
|
Gem::Specification.new do |s|
|
14
17
|
s.name = 'mwrap'
|
15
|
-
s.version =
|
18
|
+
s.version = version
|
16
19
|
s.homepage = 'https://80x24.org/mwrap/'
|
17
|
-
s.authors = ["
|
20
|
+
s.authors = ["mwrap hackers"]
|
18
21
|
s.summary = 'LD_PRELOAD malloc wrapper for Ruby'
|
19
22
|
s.executables = %w(mwrap)
|
20
23
|
s.files = manifest
|
data/test/test_mwrap.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# Copyright (C)
|
2
|
+
# Copyright (C) mwrap hackers <mwrap-public@80x24.org>
|
3
3
|
# License: GPL-2.0+ <https://www.gnu.org/licenses/gpl-2.0.txt>
|
4
4
|
require 'test/unit'
|
5
5
|
require 'mwrap'
|
@@ -29,7 +29,8 @@ class TestMwrap < Test::Unit::TestCase
|
|
29
29
|
tmp.rewind
|
30
30
|
lines = tmp.readlines
|
31
31
|
line_1 = lines.grep(/\s-e:1\b/)[0].strip
|
32
|
-
|
32
|
+
bytes = line_1.split(/\s+/)[0].to_i
|
33
|
+
assert_operator bytes, :>=, 10001
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
@@ -42,7 +43,7 @@ class TestMwrap < Test::Unit::TestCase
|
|
42
43
|
res = system(env, *cmd, { 5 => tmp })
|
43
44
|
assert res, $?.inspect
|
44
45
|
tmp.rewind
|
45
|
-
assert_match(/\
|
46
|
+
assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
|
46
47
|
|
47
48
|
env['MWRAP'] = 'dump_fd:1,dump_min:10000'
|
48
49
|
tmp.rewind
|
@@ -50,14 +51,14 @@ class TestMwrap < Test::Unit::TestCase
|
|
50
51
|
res = system(env, *cmd, { 1 => tmp })
|
51
52
|
assert res, $?.inspect
|
52
53
|
tmp.rewind
|
53
|
-
assert_match(/\
|
54
|
+
assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
|
54
55
|
|
55
56
|
tmp.rewind
|
56
57
|
tmp.truncate(0)
|
57
58
|
env['MWRAP'] = "dump_path:#{tmp.path},dump_min:10000"
|
58
59
|
res = system(env, *cmd)
|
59
60
|
assert res, $?.inspect
|
60
|
-
assert_match(/\
|
61
|
+
assert_match(/\b1\d{4}\s+[1-9]\d*\s+-e:1$/, tmp.read)
|
61
62
|
|
62
63
|
tmp.rewind
|
63
64
|
tmp.truncate(0)
|
@@ -98,7 +99,7 @@ class TestMwrap < Test::Unit::TestCase
|
|
98
99
|
tmp.rewind
|
99
100
|
buf = tmp.read
|
100
101
|
assert_not_match(/\s+-e:1$/, buf)
|
101
|
-
assert_match(/\
|
102
|
+
assert_match(/\b2\d{4}\s+[0-9]\d*\s+-e:3$/, buf)
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
@@ -176,8 +177,8 @@ class TestMwrap < Test::Unit::TestCase
|
|
176
177
|
-e GC.disable
|
177
178
|
-e keep=("0"*10000)
|
178
179
|
-e loc=Mwrap["-e:3"]
|
179
|
-
-e
|
180
|
-
)
|
180
|
+
-e
|
181
|
+
) + [ 'loc.each{|size,gen|p([size,gen,count]) if size > 10000}' ]
|
181
182
|
buf = IO.popen(@@env, cmd, &:read)
|
182
183
|
assert_predicate $?, :success?
|
183
184
|
assert_match(/\A\[\s*\d+,\s*\d+,\s*\d+\]\s*\z/s, buf)
|
@@ -230,7 +231,8 @@ class TestMwrap < Test::Unit::TestCase
|
|
230
231
|
loc.name == k or abort 'SourceLocation#name broken'
|
231
232
|
loc.total >= 10000 or abort 'SourceLocation#total broken'
|
232
233
|
loc.frees == 0 or abort 'SourceLocation#frees broken'
|
233
|
-
loc.allocations
|
234
|
+
loc.allocations >= 1 or
|
235
|
+
abort "SourceLocation#allocations broken: #{loc.allocations}"
|
234
236
|
seen = false
|
235
237
|
loc.each do |*x| seen = x end
|
236
238
|
seen[1] == loc.total or 'SourceLocation#each broken'
|
@@ -240,7 +242,9 @@ class TestMwrap < Test::Unit::TestCase
|
|
240
242
|
freed = false
|
241
243
|
until freed
|
242
244
|
freed = true
|
243
|
-
loc.each do
|
245
|
+
loc.each do |size, gen|
|
246
|
+
freed = false if size >= 10000
|
247
|
+
end
|
244
248
|
end
|
245
249
|
loc.frees == 1 or abort 'SourceLocation#frees broken (after free)'
|
246
250
|
Float === loc.mean_lifespan or abort 'mean_lifespan broken'
|
@@ -264,8 +268,9 @@ class TestMwrap < Test::Unit::TestCase
|
|
264
268
|
assert_separately(+"#{<<~"begin;"}\n#{<<~'end;'}")
|
265
269
|
begin;
|
266
270
|
require 'mwrap'
|
267
|
-
before =
|
271
|
+
before = nil
|
268
272
|
res = Mwrap.quiet do |depth|
|
273
|
+
before = __LINE__
|
269
274
|
depth == 1 or abort 'depth is not 1'
|
270
275
|
('a' * 10000).clear
|
271
276
|
Mwrap.quiet { |d| d == 2 or abort 'depth is not 2' }
|
@@ -304,7 +309,9 @@ class TestMwrap < Test::Unit::TestCase
|
|
304
309
|
gen <= GC.count && gen >= 0 or abort "bad generation: #{gen}"
|
305
310
|
(0 == (addr & 16383)) or abort "addr not aligned: #{'%x' % addr}"
|
306
311
|
end
|
307
|
-
|
312
|
+
if RUBY_VERSION.to_f < 3.1 # 3.1+ uses mmap on platforms we care about
|
313
|
+
nr == ap or abort "HeapPageBody.each missed page #{nr} != #{ap}"
|
314
|
+
end
|
308
315
|
10.times { (1..20000).to_a.map(&:to_s) }
|
309
316
|
3.times { GC.start }
|
310
317
|
Mwrap::HeapPageBody.stat(h)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mwrap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- mwrap hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: test-unit
|
@@ -55,10 +55,13 @@ files:
|
|
55
55
|
- MANIFEST
|
56
56
|
- README
|
57
57
|
- Rakefile
|
58
|
+
- VERSION-GEN
|
58
59
|
- bin/mwrap
|
59
60
|
- ext/mwrap/extconf.rb
|
60
61
|
- ext/mwrap/jhash.h
|
61
62
|
- ext/mwrap/mwrap.c
|
63
|
+
- lib/mwrap/.gitignore
|
64
|
+
- lib/mwrap/version.rb
|
62
65
|
- lib/mwrap_rack.rb
|
63
66
|
- mwrap.gemspec
|
64
67
|
- test/test_mwrap.rb
|
@@ -81,8 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
84
|
- !ruby/object:Gem::Version
|
82
85
|
version: '0'
|
83
86
|
requirements: []
|
84
|
-
|
85
|
-
rubygems_version: 2.7.7
|
87
|
+
rubygems_version: 3.0.2
|
86
88
|
signing_key:
|
87
89
|
specification_version: 4
|
88
90
|
summary: LD_PRELOAD malloc wrapper for Ruby
|