journalist 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7db826c70d439a2ee0ad1e9f9f67dfd8b6209471
4
- data.tar.gz: ce108b771e21a517521b19efec110a6a1b81a935
3
+ metadata.gz: 20db52670ef27ceb9997cad3ec0549694690276d
4
+ data.tar.gz: d0174b59664d9edede7a79aa7e4704acc2ef975f
5
5
  SHA512:
6
- metadata.gz: f49a58bff0124333d6a4fa06b5a3dcfa888aa5d94e493de4d8544dd750d3d8590090923e707932278fb701e704b7ded55c48e4cd8e3645abc0a689bc29b46c12
7
- data.tar.gz: 3000484d221a0bbe164902f6290cfc3bf8900f55e938f14691e2be5a67773ee139a5988ec2ccb29d3337d29049c2c4218a14dfed6554d1710e2e48c856697ca2
6
+ metadata.gz: 6cdc6dfc98d9ebfa1df021b5b72a53b723ac7dee90bcdaf77ae7583d1099e29746ad834423157201eed852dcfa1d9930ac878cd3081f296e1a0ccb60843aa226
7
+ data.tar.gz: 8768347c02d4d2e3d7604409388a2d06194ad849f1107f4fe88ddafb0b6acff5f365460212e5799de9518fd3411e89778ee086032ef1962fb51bba6ba8493f3b
data/README.md CHANGED
@@ -32,10 +32,11 @@ There are a lot of limitations right now, such as this only working for one proc
32
32
 
33
33
  ## TODO
34
34
 
35
- - [ ] Finish call/return tracepoints
36
- - [ ] Implement allocation tracepoints
37
- - [ ] Implement msgpack serialization
35
+ - [X] Finish call/return tracepoints
36
+ - [X] Implement allocation tracepoints
38
37
  - [ ] Implement command and stream sockets
38
+ - [ ] Implement msgpack serialization
39
+ - [ ] Implement event aggregation
39
40
  - [ ] Build GUI
40
41
 
41
42
  ## Contributing
data/Rakefile CHANGED
@@ -5,3 +5,5 @@ require "rake/extensiontask"
5
5
  Rake::ExtensionTask.new("journalist") do |ext|
6
6
  ext.lib_dir = "lib/journalist"
7
7
  end
8
+
9
+ task default: [:clobber, :compile]
@@ -0,0 +1,168 @@
1
+ #include "allocations.h"
2
+
3
+ #include "calls.h"
4
+
5
+ static struct {
6
+ VALUE newobj;
7
+ VALUE freeobj;
8
+ } allocations_tp_hook;
9
+
10
+ static struct {
11
+ int total;
12
+ st_table *allocations;
13
+ uint64_t last_sent_at;
14
+ } aggregation;
15
+
16
+ typedef struct aggregation_entry_s {
17
+ int total;
18
+ st_table *locations;
19
+ } aggregation_entry_t;
20
+
21
+ static pthread_mutex_t alloc_mutex;
22
+ static pthread_t alloc_observer;
23
+
24
+ static void
25
+ journalist_on_newobj(VALUE tpval, void *data) {
26
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
27
+
28
+ VALUE path = rb_tracearg_path(tparg);
29
+ VALUE lineno = rb_tracearg_lineno(tparg);
30
+ VALUE obj = rb_tracearg_object(tparg);
31
+
32
+ // Initialize key strings for object type and file/line pair
33
+ char *type_key = strdup(rb_obj_classname(obj));
34
+ char *loc_key = malloc(4096 * sizeof(char));
35
+ sprintf(loc_key, "%s:%d", RSTRING_PTR(path), NUM2INT(lineno));
36
+
37
+ // Start by looking up an entry.
38
+ int lookup;
39
+ aggregation_entry_t *entry = NULL;
40
+ st_data_t entry_lookup;
41
+
42
+ pthread_mutex_lock(&alloc_mutex);
43
+
44
+ lookup = st_lookup(aggregation.allocations, (st_data_t)type_key, &entry_lookup);
45
+
46
+ if(!lookup) {
47
+ // If it doesn't exist, allocate memory for one and initialize it.
48
+ entry = malloc(sizeof(aggregation_entry_t));
49
+ entry->locations = st_init_strtable_with_size(64);
50
+ entry->total = 0;
51
+
52
+ st_insert(aggregation.allocations, (st_data_t)strdup(type_key), (st_data_t)entry);
53
+ } else {
54
+ // If it does exist, get the address.
55
+ entry = (aggregation_entry_t *)entry_lookup;
56
+ }
57
+
58
+ entry->total++;
59
+
60
+ // Get or initialize the allocations for
61
+ int file_allocations = 0;
62
+ lookup = st_lookup(entry->locations, (st_data_t)loc_key, (st_data_t *)&file_allocations);
63
+
64
+ if(!lookup) file_allocations = 0;
65
+ file_allocations++;
66
+
67
+ st_insert(entry->locations, (st_data_t)strdup(loc_key), (st_data_t)file_allocations);
68
+
69
+ aggregation.total++;
70
+
71
+ pthread_mutex_unlock(&alloc_mutex);
72
+
73
+ free(type_key);
74
+ free(loc_key);
75
+ }
76
+
77
+ static void
78
+ journalist_on_freeobj(VALUE tpval, void *data) {
79
+ // rb_journalist_socket_send("freeobj\n");
80
+ }
81
+
82
+ static int
83
+ journalist_allocations_send_locations(st_data_t key, st_data_t value, st_data_t data) {
84
+ char *type = (char *)data;
85
+ char *location = (char *)key;
86
+ int total = (int)value;
87
+
88
+ char message[4096];
89
+ sprintf(message, "newobj_loc: type %s loc %s count %d\n",
90
+ type, location, total);
91
+
92
+ rb_journalist_socket_send(message);
93
+
94
+ return ST_CONTINUE;
95
+ }
96
+
97
+ static int
98
+ journalist_allocations_send_types(st_data_t key, st_data_t value, st_data_t _) {
99
+ char *type = (char *)key;
100
+ aggregation_entry_t *entry = (aggregation_entry_t *)value;
101
+
102
+ char message[4096];
103
+ sprintf(message, "newobj: type %s count %d\n",
104
+ type, entry->total);
105
+
106
+ rb_journalist_socket_send(message);
107
+
108
+ st_foreach(entry->locations, journalist_allocations_send_locations, key);
109
+ st_free_table(entry->locations);
110
+
111
+ free(entry);
112
+
113
+ return ST_CONTINUE;
114
+ }
115
+
116
+ void *
117
+ journalist_allocations_observer(void *threadid) {
118
+ uint64_t current_time, last_sent_ago;
119
+ do {
120
+ current_time = timeofday_usec();
121
+ last_sent_ago = current_time - aggregation.last_sent_at;
122
+
123
+ pthread_mutex_lock(&alloc_mutex);
124
+ if((last_sent_ago > 500000 && aggregation.total > 0) || aggregation.total > 100000) {
125
+ // Iterate through the table.
126
+ st_foreach(aggregation.allocations, journalist_allocations_send_types, 0);
127
+
128
+ // Clear data.
129
+ st_clear(aggregation.allocations);
130
+ aggregation.total = 0;
131
+ aggregation.last_sent_at = current_time;
132
+ }
133
+
134
+ pthread_mutex_unlock(&alloc_mutex);
135
+ usleep(500000);
136
+ } while(1);
137
+
138
+ return 0;
139
+ }
140
+
141
+ void
142
+ rb_journalist_allocations_init() {
143
+ allocations_tp_hook.newobj = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, journalist_on_newobj, 0);
144
+ allocations_tp_hook.freeobj = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, journalist_on_freeobj, 0);
145
+
146
+ rb_gc_register_address(&allocations_tp_hook.newobj);
147
+ rb_gc_register_address(&allocations_tp_hook.freeobj);
148
+
149
+ aggregation.total = 0;
150
+ aggregation.allocations = st_init_strtable_with_size(1024);
151
+ aggregation.last_sent_at = timeofday_usec();
152
+
153
+ pthread_mutex_init(&alloc_mutex, 0);
154
+ }
155
+
156
+ void
157
+ rb_journalist_allocations_start() {
158
+ rb_tracepoint_enable(allocations_tp_hook.newobj);
159
+ rb_tracepoint_enable(allocations_tp_hook.freeobj);
160
+
161
+ pthread_create(&alloc_observer, 0, journalist_allocations_observer, 0);
162
+ }
163
+
164
+ void
165
+ rb_journalist_allocations_stop() {
166
+ rb_tracepoint_disable(allocations_tp_hook.newobj);
167
+ rb_tracepoint_disable(allocations_tp_hook.freeobj);
168
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef ALLOCATIONS_H
2
+ #define ALLOCATIONS_H 1
3
+
4
+ #include "journalist.h"
5
+
6
+ void rb_journalist_allocations_init();
7
+ void rb_journalist_allocations_start();
8
+ void rb_journalist_allocations_stop();
9
+
10
+ #endif /* ALLOCATIONS_H */
@@ -11,7 +11,7 @@ static struct {
11
11
  static int stack_size = 0;
12
12
 
13
13
  const char c_call_fmt[] = "c_call: "
14
- "class %s method: %s class_method %d stack_depth %d "
14
+ "class %s method %s class_method %d stack_depth %d "
15
15
  "path %s line %d\n";
16
16
 
17
17
  static void
@@ -22,15 +22,14 @@ journalist_on_call_c_call(VALUE tpval, void *data) {
22
22
  VALUE method_id = rb_tracearg_method_id(tparg);
23
23
  VALUE path = rb_tracearg_path(tparg);
24
24
  VALUE lineno = rb_tracearg_lineno(tparg);
25
-
26
- bool instance = TYPE(self) == T_CLASS || TYPE(self) == T_MODULE;
25
+ bool singleton = TYPE(self) == T_CLASS || TYPE(self) == T_MODULE;
27
26
 
28
27
  char buffer[4096];
29
28
  sprintf(buffer,
30
29
  c_call_fmt,
31
30
  rb_obj_classname(self),
32
31
  rb_id2name(SYM2ID(method_id)),
33
- instance,
32
+ singleton,
34
33
  stack_size,
35
34
  RSTRING_PTR(path),
36
35
  NUM2INT(lineno)
@@ -8,12 +8,14 @@ rb_journalist_init() {
8
8
 
9
9
  rb_journalist_gc_init();
10
10
  rb_journalist_calls_init();
11
+ rb_journalist_allocations_init();
11
12
  }
12
13
 
13
14
  static VALUE
14
15
  journalist_start(VALUE klass) {
15
16
  rb_journalist_gc_start();
16
17
  rb_journalist_calls_start();
18
+ rb_journalist_allocations_start();
17
19
 
18
20
  return Qtrue;
19
21
  }
@@ -22,6 +24,7 @@ static VALUE
22
24
  journalist_stop(VALUE klass) {
23
25
  rb_journalist_gc_stop();
24
26
  rb_journalist_calls_stop();
27
+ rb_journalist_allocations_stop();
25
28
 
26
29
  return Qtrue;
27
30
  }
@@ -36,3 +39,11 @@ Init_journalist(void)
36
39
 
37
40
  rb_journalist_init();
38
41
  }
42
+
43
+ uint64_t
44
+ timeofday_usec() {
45
+ struct timeval tv;
46
+ gettimeofday(&tv, NULL);
47
+ return (uint64_t)tv.tv_sec*1e6 +
48
+ (uint64_t)tv.tv_usec;
49
+ }
@@ -1,13 +1,20 @@
1
1
  #ifndef JOURNALIST_H
2
2
  #define JOURNALIST_H 1
3
3
 
4
+ #include <pthread.h>
4
5
  #include <stdbool.h>
6
+ #include <stdio.h>
7
+ #include <sys/time.h>
8
+ #include <time.h>
5
9
 
6
10
  #include "ruby.h"
7
11
  #include "ruby/debug.h"
8
12
 
13
+ #include "allocations.h"
9
14
  #include "calls.h"
10
15
  #include "garbage_collection.h"
11
16
  #include "socket.h"
12
17
 
18
+ uint64_t timeofday_usec();
19
+
13
20
  #endif /* JOURNALIST_H */
@@ -1,15 +1,31 @@
1
1
  #include "socket.h"
2
2
 
3
+ static pthread_mutex_t sock_mutex = PTHREAD_MUTEX_INITIALIZER;
4
+
3
5
  FILE *journalist_file;
4
- static char journalist_file_path[] = "/tmp/journalist";
6
+ static char journalist_file_path_fmt[] = "/tmp/journalist-%d";
5
7
 
6
8
  void
7
9
  rb_journalist_socket_init() {
8
- journalist_file = fopen(journalist_file_path, "w");
10
+ pid_t pid = getpid();
11
+
12
+ char path[1024];
13
+ snprintf(
14
+ path,
15
+ 1024,
16
+ journalist_file_path_fmt,
17
+ pid
18
+ );
19
+
20
+ journalist_file = fopen(path, "w");
9
21
  }
10
22
 
11
23
  void
12
24
  rb_journalist_socket_send(char *message) {
25
+ pthread_mutex_lock(&sock_mutex);
26
+
13
27
  fwrite(message, sizeof(char), strlen(message), journalist_file);
14
28
  fflush(journalist_file);
29
+
30
+ pthread_mutex_unlock(&sock_mutex);
15
31
  }
@@ -1,14 +1,13 @@
1
- #ifndef ASDASDASD
2
- #define ASDASDASD 1
1
+ #ifndef SOCKET_H
2
+ #define SOCKET_H 1
3
3
 
4
- #include <stdio.h>
5
- #include <sys/socket.h>
6
- #include <sys/un.h>
7
4
  #include <stdlib.h>
8
5
  #include <string.h>
9
6
  #include <unistd.h>
10
7
 
8
+ #include "journalist.h"
9
+
11
10
  void rb_journalist_socket_init();
12
11
  void rb_journalist_socket_send(char *message);
13
12
 
14
- #endif /* ASDASDASD */
13
+ #endif /* SOCKET_H */
@@ -1,3 +1,3 @@
1
1
  module Journalist
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: journalist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andre Medeiros
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-18 00:00:00.000000000 Z
11
+ date: 2014-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,6 +67,8 @@ files:
67
67
  - LICENSE.txt
68
68
  - README.md
69
69
  - Rakefile
70
+ - ext/journalist/allocations.c
71
+ - ext/journalist/allocations.h
70
72
  - ext/journalist/calls.c
71
73
  - ext/journalist/calls.h
72
74
  - ext/journalist/extconf.rb