raindrops 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.3.0.GIT
4
+ DEF_VER=v0.4.0.GIT
5
5
 
6
6
  LF='
7
7
  '
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.1
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
- raindrops requires GCC 4.x (or compatible) or later to support the
39
- atomic builtins (__sync_{add,sub}_and_fetch()). Atomic operations on
40
- other compilers may be supported if there is demand.
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://rainbows.bogomips.org/"
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
@@ -1,2 +1 @@
1
- * more portable atomics for non-GCC systems (libatomicops?)
2
1
  * pure Ruby version for non-forking servers
@@ -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 = __sync_add_and_fetch(&g_seq, 1);
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)
@@ -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
- #ifndef CACHE_LINE_SIZE
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
- union {
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, sizeof(struct raindrop) * r->size);
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, sizeof(struct raindrop) * r->size,
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, sizeof(struct raindrop) * src->size);
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) * sizeof(struct raindrop);
105
+ unsigned long off = FIX2ULONG(index) * raindrop_size;
104
106
 
105
- if (off >= sizeof(struct raindrop) * r->size)
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 += sizeof(struct raindrop);
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.3.0
5
- VERSION = '0.3.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
@@ -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
@@ -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: 19
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 0.3.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-07-10 00:00:00 +00:00
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