journalist 0.0.1 → 0.0.2

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 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