raindrops 0.3.0 → 0.4.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.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -1
- data/README +13 -5
- data/Rakefile +1 -1
- data/TODO +0 -1
- data/ext/raindrops/extconf.rb +26 -0
- data/ext/raindrops/linux_inet_diag.c +1 -1
- data/ext/raindrops/raindrops.c +40 -13
- data/ext/raindrops/raindrops_atomic.h +23 -0
- data/lib/raindrops.rb +2 -2
- data/test/test_raindrops.rb +6 -0
- data/test/test_raindrops_gc.rb +4 -1
- metadata +6 -6
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
|
@@ -53,7 +53,7 @@ NEWS: GIT-VERSION-FILE
|
|
|
53
53
|
latest: NEWS
|
|
54
54
|
@awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' $<
|
|
55
55
|
|
|
56
|
-
SINCE = 0.2.
|
|
56
|
+
SINCE = 0.2.0
|
|
57
57
|
ChangeLog: LOG_VERSION = \
|
|
58
58
|
$(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
|
|
59
59
|
echo $(GIT_VERSION) || git describe)
|
data/README
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
Raindrops is a real time stats package to show statistics for Rack HTTP
|
|
4
4
|
servers. It is designed for preforking servers such as Rainbows! and
|
|
5
5
|
Unicorn, but should support any Rack HTTP server under Ruby 1.9, 1.8 and
|
|
6
|
-
possibly Rubinius (untested) on platforms supporting POSIX shared memory
|
|
7
|
-
and compiled with GCC (for atomic builtins).
|
|
6
|
+
possibly Rubinius (untested) on platforms supporting POSIX shared memory.
|
|
8
7
|
|
|
9
8
|
Raindrops includes a Struct-like Raindrops::Struct class that may be used
|
|
10
9
|
standalone to create atomic counters shared across any number of forked
|
|
@@ -35,9 +34,12 @@ processes under SMP.
|
|
|
35
34
|
|
|
36
35
|
== Install
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
atomic builtins
|
|
40
|
-
|
|
37
|
+
We recommend GCC 4+ (or compatible) to support the
|
|
38
|
+
{atomic builtins}[http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html]
|
|
39
|
+
(__sync_{add,sub}_and_fetch()). For non-GCC 4+ users, we also support
|
|
40
|
+
compilation with the
|
|
41
|
+
{libatomic_ops}[http://www.hpl.hp.com/research/linux/atomic_ops/]
|
|
42
|
+
package starting with Raindrops 0.4.0.
|
|
41
43
|
|
|
42
44
|
If you're using a packaged Ruby distribution, make sure you have a C
|
|
43
45
|
compiler and the matching Ruby development libraries and headers.
|
|
@@ -115,6 +117,12 @@ git itself. See the Documentation/SubmittingPatches document
|
|
|
115
117
|
distributed with git on on patch submission guidelines to follow. Just
|
|
116
118
|
don't email the git mailing list or maintainer with raindrops patches.
|
|
117
119
|
|
|
120
|
+
raindrops is currently dual-licensed under the LGPLv2.1 and LGPLv3. To
|
|
121
|
+
allow for a transition to future versions of the LGPL, contributors are
|
|
122
|
+
required to sign-off changes allowing allowing the project leader to
|
|
123
|
+
relicense raindrops under newer versions of the LGPL (which should be
|
|
124
|
+
similar in spirit to the existing LGPL).
|
|
125
|
+
|
|
118
126
|
== Contact
|
|
119
127
|
|
|
120
128
|
All feedback (bug reports, user/development discussion, patches, pull
|
data/Rakefile
CHANGED
|
@@ -25,7 +25,7 @@ end
|
|
|
25
25
|
|
|
26
26
|
cgit_url = "http://git.bogomips.org/cgit/raindrops.git"
|
|
27
27
|
git_url = ENV['GIT_URL'] || 'git://git.bogomips.org/raindrops.git'
|
|
28
|
-
web_url = "http://
|
|
28
|
+
web_url = "http://raindrops.bogomips.org/"
|
|
29
29
|
|
|
30
30
|
desc 'prints news as an Atom feed'
|
|
31
31
|
task :news_atom do
|
data/TODO
CHANGED
data/ext/raindrops/extconf.rb
CHANGED
|
@@ -7,5 +7,31 @@ have_func('munmap', 'sys/mman.h') or abort 'munmap() not found'
|
|
|
7
7
|
have_func("rb_struct_alloc_noinit")
|
|
8
8
|
have_func('rb_thread_blocking_region')
|
|
9
9
|
|
|
10
|
+
checking_for "GCC 4+ atomic builtins" do
|
|
11
|
+
src = <<SRC
|
|
12
|
+
int main(int argc, char * const argv[]) {
|
|
13
|
+
volatile unsigned long i = 0;
|
|
14
|
+
__sync_add_and_fetch(&i, argc);
|
|
15
|
+
__sync_sub_and_fetch(&i, argc);
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
SRC
|
|
19
|
+
|
|
20
|
+
if try_run(src)
|
|
21
|
+
$defs.push(format("-DHAVE_GCC_ATOMIC_BUILTINS"))
|
|
22
|
+
true
|
|
23
|
+
else
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end or have_header('atomic_ops.h') or abort <<-SRC
|
|
27
|
+
|
|
28
|
+
libatomic_ops is required if GCC 4+ is not used.
|
|
29
|
+
See http://www.hpl.hp.com/research/linux/atomic_ops/
|
|
30
|
+
|
|
31
|
+
Users of Debian-based distros may run:
|
|
32
|
+
|
|
33
|
+
apt-get install libatomic-ops-dev
|
|
34
|
+
SRC
|
|
35
|
+
|
|
10
36
|
dir_config('raindrops')
|
|
11
37
|
create_makefile('raindrops_ext')
|
|
@@ -144,7 +144,7 @@ static VALUE diag(void *ptr)
|
|
|
144
144
|
} req;
|
|
145
145
|
struct msghdr msg;
|
|
146
146
|
const char *err = NULL;
|
|
147
|
-
unsigned seq =
|
|
147
|
+
unsigned seq = ++g_seq; /* not atomic, rely on GVL for now */
|
|
148
148
|
int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG);
|
|
149
149
|
|
|
150
150
|
if (fd < 0)
|
data/ext/raindrops/raindrops.c
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
#include <ruby.h>
|
|
2
|
+
#include <unistd.h>
|
|
2
3
|
#include <sys/mman.h>
|
|
3
4
|
#include <assert.h>
|
|
4
5
|
#include <errno.h>
|
|
5
6
|
#include <stddef.h>
|
|
7
|
+
#include "raindrops_atomic.h"
|
|
8
|
+
|
|
9
|
+
#ifndef SIZET2NUM
|
|
10
|
+
# define SIZET2NUM(x) ULONG2NUM(x)
|
|
11
|
+
#endif
|
|
6
12
|
|
|
7
13
|
/*
|
|
8
14
|
* most modern CPUs have a cache-line size of 64 or 128.
|
|
9
15
|
* We choose a bigger one by default since our structure is not
|
|
10
16
|
* heavily used
|
|
11
17
|
*/
|
|
12
|
-
|
|
13
|
-
# define CACHE_LINE_SIZE 128
|
|
14
|
-
#endif
|
|
18
|
+
static size_t raindrop_size = 128;
|
|
15
19
|
|
|
16
20
|
/* each raindrop is a counter */
|
|
17
21
|
struct raindrop {
|
|
18
|
-
|
|
19
|
-
unsigned long counter;
|
|
20
|
-
unsigned char padding[CACHE_LINE_SIZE];
|
|
21
|
-
} as;
|
|
22
|
+
unsigned long counter;
|
|
22
23
|
} __attribute__((packed));
|
|
23
24
|
|
|
24
25
|
/* allow mmap-ed regions can store more than one raindrop */
|
|
@@ -33,7 +34,7 @@ static void evaporate(void *ptr)
|
|
|
33
34
|
struct raindrops *r = ptr;
|
|
34
35
|
|
|
35
36
|
if (r->drops) {
|
|
36
|
-
int rv = munmap(r->drops,
|
|
37
|
+
int rv = munmap(r->drops, raindrop_size * r->size);
|
|
37
38
|
if (rv != 0)
|
|
38
39
|
rb_bug("munmap failed in gc: %s", strerror(errno));
|
|
39
40
|
}
|
|
@@ -72,9 +73,10 @@ static VALUE init(VALUE self, VALUE size)
|
|
|
72
73
|
rb_raise(rb_eArgError, "size must be >= 1");
|
|
73
74
|
|
|
74
75
|
retry:
|
|
75
|
-
r->drops = mmap(NULL,
|
|
76
|
+
r->drops = mmap(NULL, raindrop_size * r->size,
|
|
76
77
|
PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
|
|
77
78
|
if (r->drops == MAP_FAILED) {
|
|
79
|
+
r->drops = NULL;
|
|
78
80
|
if ((errno == EAGAIN || errno == ENOMEM) && tries-- > 0) {
|
|
79
81
|
rb_gc();
|
|
80
82
|
goto retry;
|
|
@@ -92,7 +94,7 @@ static VALUE init_copy(VALUE dest, VALUE source)
|
|
|
92
94
|
struct raindrops *src = get(source);
|
|
93
95
|
|
|
94
96
|
init(dest, LONG2NUM(src->size));
|
|
95
|
-
memcpy(dst->drops, src->drops,
|
|
97
|
+
memcpy(dst->drops, src->drops, raindrop_size * src->size);
|
|
96
98
|
|
|
97
99
|
return dest;
|
|
98
100
|
}
|
|
@@ -100,9 +102,9 @@ static VALUE init_copy(VALUE dest, VALUE source)
|
|
|
100
102
|
static unsigned long *addr_of(VALUE self, VALUE index)
|
|
101
103
|
{
|
|
102
104
|
struct raindrops *r = get(self);
|
|
103
|
-
unsigned long off = FIX2ULONG(index) *
|
|
105
|
+
unsigned long off = FIX2ULONG(index) * raindrop_size;
|
|
104
106
|
|
|
105
|
-
if (off >=
|
|
107
|
+
if (off >= raindrop_size * r->size)
|
|
106
108
|
rb_raise(rb_eArgError, "offset overrun");
|
|
107
109
|
|
|
108
110
|
return (unsigned long *)((unsigned long)r->drops + off);
|
|
@@ -143,7 +145,7 @@ static VALUE to_ary(VALUE self)
|
|
|
143
145
|
|
|
144
146
|
for (i = 0; i < r->size; i++) {
|
|
145
147
|
rb_ary_push(rv, ULONG2NUM(*((unsigned long *)base)));
|
|
146
|
-
base +=
|
|
148
|
+
base += raindrop_size;
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
return rv;
|
|
@@ -172,9 +174,34 @@ static VALUE aref(VALUE self, VALUE index)
|
|
|
172
174
|
void Init_raindrops_linux_inet_diag(void);
|
|
173
175
|
#endif
|
|
174
176
|
|
|
177
|
+
#ifndef _SC_NPROCESSORS_ONLN
|
|
178
|
+
# ifdef _SC_NPROC_ONLN
|
|
179
|
+
# define _SC_NPROCESSORS_ONLN _SC_NPROC_ONLN
|
|
180
|
+
# elif defined _SC_CRAY_NCPU
|
|
181
|
+
# define _SC_NPROCESSORS_ONLN _SC_CRAY_NCPU
|
|
182
|
+
# endif
|
|
183
|
+
#endif
|
|
184
|
+
|
|
175
185
|
void Init_raindrops_ext(void)
|
|
176
186
|
{
|
|
177
187
|
VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
|
|
188
|
+
long tmp = 2;
|
|
189
|
+
|
|
190
|
+
#ifdef _SC_NPROCESSORS_ONLN
|
|
191
|
+
tmp = sysconf(_SC_NPROCESSORS_ONLN);
|
|
192
|
+
#endif
|
|
193
|
+
/* no point in padding on single CPU machines */
|
|
194
|
+
if (tmp == 1)
|
|
195
|
+
raindrop_size = sizeof(unsigned long);
|
|
196
|
+
#ifdef _SC_LEVEL1_DCACHE_LINESIZE
|
|
197
|
+
if (tmp != 1) {
|
|
198
|
+
tmp = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
|
|
199
|
+
if (tmp > 0)
|
|
200
|
+
raindrop_size = (size_t)tmp;
|
|
201
|
+
}
|
|
202
|
+
#endif
|
|
203
|
+
rb_define_const(cRaindrops, "SIZE", SIZET2NUM(raindrop_size));
|
|
204
|
+
|
|
178
205
|
rb_define_alloc_func(cRaindrops, alloc);
|
|
179
206
|
|
|
180
207
|
rb_define_method(cRaindrops, "initialize", init, 1);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* use wrappers around libatomic-ops for folks that don't have GCC
|
|
3
|
+
* or a new enough version of GCC
|
|
4
|
+
*/
|
|
5
|
+
#ifndef HAVE_GCC_ATOMIC_BUILTINS
|
|
6
|
+
#include <atomic_ops.h>
|
|
7
|
+
|
|
8
|
+
static inline unsigned long
|
|
9
|
+
__sync_add_and_fetch(unsigned long *dst, unsigned long incr)
|
|
10
|
+
{
|
|
11
|
+
AO_t tmp = AO_fetch_and_add((AO_t *)dst, (AO_t)incr);
|
|
12
|
+
|
|
13
|
+
return (unsigned long)tmp + incr;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static inline unsigned long
|
|
17
|
+
__sync_sub_and_fetch(unsigned long *dst, unsigned long incr)
|
|
18
|
+
{
|
|
19
|
+
AO_t tmp = AO_fetch_and_add((AO_t *)dst, (AO_t)(-(long)incr));
|
|
20
|
+
|
|
21
|
+
return (unsigned long)tmp - incr;
|
|
22
|
+
}
|
|
23
|
+
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
|
data/lib/raindrops.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# -*- encoding: binary -*-
|
|
2
2
|
class Raindrops
|
|
3
3
|
|
|
4
|
-
# Raindrops is currently at version 0.
|
|
5
|
-
VERSION = '0.
|
|
4
|
+
# Raindrops is currently at version 0.4.0
|
|
5
|
+
VERSION = '0.4.0'
|
|
6
6
|
|
|
7
7
|
# Used to represent the number of +active+ and +queued+ sockets for
|
|
8
8
|
# a single listen socket across all threads and processes on a
|
data/test/test_raindrops.rb
CHANGED
|
@@ -4,6 +4,12 @@ require 'raindrops'
|
|
|
4
4
|
|
|
5
5
|
class TestRaindrops < Test::Unit::TestCase
|
|
6
6
|
|
|
7
|
+
def test_raindrop_size
|
|
8
|
+
assert_kind_of Integer, Raindrops::SIZE
|
|
9
|
+
assert Raindrops::SIZE > 0
|
|
10
|
+
puts "Raindrops::SIZE = #{Raindrops::SIZE}"
|
|
11
|
+
end
|
|
12
|
+
|
|
7
13
|
def test_size
|
|
8
14
|
rd = Raindrops.new(4)
|
|
9
15
|
assert_equal 4, rd.size
|
data/test/test_raindrops_gc.rb
CHANGED
|
@@ -4,9 +4,12 @@ require 'raindrops'
|
|
|
4
4
|
|
|
5
5
|
class TestRaindropsGc < Test::Unit::TestCase
|
|
6
6
|
|
|
7
|
+
# we may need to create more garbage as GC may be less aggressive
|
|
8
|
+
# about expiring things. This is completely unrealistic code,
|
|
9
|
+
# though...
|
|
7
10
|
def test_gc
|
|
8
11
|
assert_nothing_raised do
|
|
9
|
-
1000000.times { Raindrops.new(24) }
|
|
12
|
+
1000000.times { |i| Raindrops.new(24); [] }
|
|
10
13
|
end
|
|
11
14
|
end
|
|
12
15
|
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: raindrops
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 15
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
8
|
+
- 4
|
|
9
9
|
- 0
|
|
10
|
-
version: 0.
|
|
10
|
+
version: 0.4.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- raindrops hackers
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2010-
|
|
18
|
+
date: 2010-09-21 00:00:00 +00:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies: []
|
|
21
21
|
|
|
@@ -23,8 +23,7 @@ description: |-
|
|
|
23
23
|
Raindrops is a real time stats package to show statistics for Rack HTTP
|
|
24
24
|
servers. It is designed for preforking servers such as Rainbows! and
|
|
25
25
|
Unicorn, but should support any Rack HTTP server under Ruby 1.9, 1.8 and
|
|
26
|
-
possibly Rubinius (untested) on platforms supporting POSIX shared memory
|
|
27
|
-
and compiled with GCC (for atomic builtins).
|
|
26
|
+
possibly Rubinius (untested) on platforms supporting POSIX shared memory.
|
|
28
27
|
email: raindrops@librelist.com
|
|
29
28
|
executables: []
|
|
30
29
|
|
|
@@ -59,6 +58,7 @@ files:
|
|
|
59
58
|
- ext/raindrops/extconf.rb
|
|
60
59
|
- ext/raindrops/linux_inet_diag.c
|
|
61
60
|
- ext/raindrops/raindrops.c
|
|
61
|
+
- ext/raindrops/raindrops_atomic.h
|
|
62
62
|
- lib/raindrops.rb
|
|
63
63
|
- lib/raindrops/linux.rb
|
|
64
64
|
- lib/raindrops/middleware.rb
|