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 +4 -4
- data/README.md +4 -3
- data/Rakefile +2 -0
- data/ext/journalist/allocations.c +168 -0
- data/ext/journalist/allocations.h +10 -0
- data/ext/journalist/calls.c +3 -4
- data/ext/journalist/journalist.c +11 -0
- data/ext/journalist/journalist.h +7 -0
- data/ext/journalist/socket.c +18 -2
- data/ext/journalist/socket.h +5 -6
- data/lib/journalist/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 20db52670ef27ceb9997cad3ec0549694690276d
|
|
4
|
+
data.tar.gz: d0174b59664d9edede7a79aa7e4704acc2ef975f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
- [
|
|
36
|
-
- [
|
|
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
|
@@ -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
|
+
}
|
data/ext/journalist/calls.c
CHANGED
|
@@ -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
|
|
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
|
-
|
|
32
|
+
singleton,
|
|
34
33
|
stack_size,
|
|
35
34
|
RSTRING_PTR(path),
|
|
36
35
|
NUM2INT(lineno)
|
data/ext/journalist/journalist.c
CHANGED
|
@@ -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
|
+
}
|
data/ext/journalist/journalist.h
CHANGED
|
@@ -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 */
|
data/ext/journalist/socket.c
CHANGED
|
@@ -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
|
|
6
|
+
static char journalist_file_path_fmt[] = "/tmp/journalist-%d";
|
|
5
7
|
|
|
6
8
|
void
|
|
7
9
|
rb_journalist_socket_init() {
|
|
8
|
-
|
|
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
|
}
|
data/ext/journalist/socket.h
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
#ifndef
|
|
2
|
-
#define
|
|
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 /*
|
|
13
|
+
#endif /* SOCKET_H */
|
data/lib/journalist/version.rb
CHANGED
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.
|
|
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-
|
|
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
|