Skip to content

Commit 5214188

Browse files
committed
page profile
1 parent 67c7843 commit 5214188

File tree

5 files changed

+318
-13
lines changed

5 files changed

+318
-13
lines changed

src/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ SRCS := \
4444
jltypes gf typemap smallintset ast builtins module interpreter symbol \
4545
dlload sys init task array genericmemory staticdata toplevel jl_uv datatype \
4646
simplevector runtime_intrinsics precompile jloptions mtarraylist \
47-
threading scheduler stackwalk gc gc-debug gc-pages gc-stacks gc-alloc-profiler method \
47+
threading scheduler stackwalk gc gc-debug gc-pages gc-stacks gc-alloc-profiler gc-page-profiler method \
4848
jlapi signal-handling safepoint timing subtype rtutils gc-heap-snapshot \
4949
crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage runtime_ccall
5050

src/gc-page-profiler.c

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
// This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
#include "gc-page-profiler.h"
4+
5+
#ifdef __cplusplus
6+
extern "C" {
7+
#endif
8+
9+
// whether page profiling is enabled
10+
int page_profile_enabled;
11+
// number of pages written
12+
size_t page_profile_pages_written;
13+
// stream to write page profile to
14+
ios_t *page_profile_stream;
15+
// mutex for page profile
16+
uv_mutex_t page_profile_lock;
17+
18+
#define GC_SERIALIZER_EMPTY ((const char *)0x1)
19+
#define GC_SERIALIZER_GARBAGE ((const char *)0x2)
20+
21+
gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT
22+
{
23+
gc_page_profiler_serializer_t serializer;
24+
serializer.length = 0;
25+
serializer.capacity = GC_PAGE_SZ;
26+
if (__unlikely(page_profile_enabled)) {
27+
serializer.buffer = (char const **)calloc_s(serializer.capacity);
28+
}
29+
else {
30+
serializer.buffer = NULL;
31+
}
32+
return serializer;
33+
}
34+
35+
void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer,
36+
jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT
37+
{
38+
if (__unlikely(page_profile_enabled)) {
39+
memset(serializer->buffer, 0, serializer->capacity);
40+
serializer->length = 0;
41+
serializer->data = (char *)pg->data;
42+
serializer->osize = pg->osize;
43+
}
44+
}
45+
46+
void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT
47+
{
48+
free(serializer->buffer);
49+
}
50+
51+
void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer,
52+
const char *str) JL_NOTSAFEPOINT
53+
{
54+
serializer->buffer[serializer->length++] = str;
55+
}
56+
57+
void gc_enable_page_profile(void) JL_NOTSAFEPOINT
58+
{
59+
page_profile_enabled = 1;
60+
}
61+
62+
void gc_disable_page_profile(void) JL_NOTSAFEPOINT
63+
{
64+
page_profile_enabled = 0;
65+
}
66+
67+
void gc_page_profile_write_empty_page(gc_page_profiler_serializer_t *serializer)
68+
JL_NOTSAFEPOINT
69+
{
70+
if (__unlikely(page_profile_enabled)) {
71+
gc_page_serializer_write(serializer, GC_SERIALIZER_EMPTY);
72+
}
73+
}
74+
75+
void gc_page_profile_write_garbage(gc_page_profiler_serializer_t *serializer)
76+
JL_NOTSAFEPOINT
77+
{
78+
if (__unlikely(page_profile_enabled)) {
79+
gc_page_serializer_write(serializer, GC_SERIALIZER_GARBAGE);
80+
}
81+
}
82+
83+
void gc_page_profile_write_live_obj(gc_page_profiler_serializer_t *serializer,
84+
jl_taggedvalue_t *v) JL_NOTSAFEPOINT
85+
{
86+
if (__unlikely(page_profile_enabled)) {
87+
const char *name = jl_typeof_str(jl_valueof(v));
88+
gc_page_serializer_write(serializer, name);
89+
}
90+
}
91+
92+
// inspired by the function from `src/gc-heap-snapshot.cpp`
93+
void gc_page_profile_print_escape_json(ios_t *stream, const char *s,
94+
size_t len) JL_NOTSAFEPOINT
95+
{
96+
{
97+
for (size_t i = 0; i < len; i++) {
98+
const char *c = &s[i];
99+
switch (*c) {
100+
case '\\': ios_write(stream, "\\\\", 2); break;
101+
case '\b': ios_write(stream, "\\b", 2); break;
102+
case '\f': ios_write(stream, "\\f", 2); break;
103+
case '\n': ios_write(stream, "\\n", 2); break;
104+
case '\r': ios_write(stream, "\\r", 2); break;
105+
case '\t': ios_write(stream, "\\t", 2); break;
106+
default:
107+
if (('\x00' <= *c) & (*c <= '\x1f')) {
108+
ios_printf(stream, "\\u%04x", (int)*c);
109+
}
110+
else {
111+
ios_putc(*c, stream);
112+
}
113+
}
114+
}
115+
}
116+
}
117+
118+
void gc_page_profile_write_preamble(gc_page_profiler_serializer_t *serializer)
119+
JL_NOTSAFEPOINT
120+
{
121+
if (__unlikely(page_profile_enabled)) {
122+
char str[GC_TYPE_STR_MAXLEN];
123+
memset(str, 0, GC_TYPE_STR_MAXLEN);
124+
snprintf(str, GC_TYPE_STR_MAXLEN, "{");
125+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
126+
memset(str, 0, GC_TYPE_STR_MAXLEN);
127+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"address\": \"%p\",", serializer->data);
128+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
129+
memset(str, 0, GC_TYPE_STR_MAXLEN);
130+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"object_size\": %d,", serializer->osize);
131+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
132+
memset(str, 0, GC_TYPE_STR_MAXLEN);
133+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"objects\": [");
134+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
135+
}
136+
}
137+
138+
void gc_page_profile_write_epilogue(gc_page_profiler_serializer_t *serializer)
139+
JL_NOTSAFEPOINT
140+
{
141+
if (__unlikely(page_profile_enabled)) {
142+
char str[GC_TYPE_STR_MAXLEN];
143+
memset(str, 0, GC_TYPE_STR_MAXLEN);
144+
snprintf(str, GC_TYPE_STR_MAXLEN, "]");
145+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
146+
memset(str, 0, GC_TYPE_STR_MAXLEN);
147+
snprintf(str, GC_TYPE_STR_MAXLEN, "}");
148+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
149+
}
150+
}
151+
152+
void gc_page_profile_write_comma(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT
153+
{
154+
if (__unlikely(page_profile_enabled)) {
155+
if (page_profile_pages_written > 0) {
156+
char str[GC_TYPE_STR_MAXLEN];
157+
memset(str, 0, GC_TYPE_STR_MAXLEN);
158+
snprintf(str, GC_TYPE_STR_MAXLEN, ",");
159+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
160+
}
161+
}
162+
}
163+
164+
void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer)
165+
JL_NOTSAFEPOINT
166+
{
167+
if (__unlikely(page_profile_enabled)) {
168+
// write to file
169+
uv_mutex_lock(&page_profile_lock);
170+
gc_page_profile_write_comma(serializer);
171+
gc_page_profile_write_preamble(serializer);
172+
char str[GC_TYPE_STR_MAXLEN];
173+
for (size_t i = 0; i < serializer->length; i++) {
174+
memset(str, 0, GC_TYPE_STR_MAXLEN);
175+
if (serializer->buffer[i] == GC_SERIALIZER_EMPTY) {
176+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"empty\",");
177+
}
178+
else if (serializer->buffer[i] == GC_SERIALIZER_GARBAGE) {
179+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"garbage\",");
180+
}
181+
else {
182+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"%s\",", serializer->buffer[i]);
183+
}
184+
if (i == serializer->length - 1) {
185+
str[strlen(str) - 1] = '\0';
186+
}
187+
gc_page_profile_print_escape_json(page_profile_stream, str, strlen(str));
188+
}
189+
gc_page_profile_write_epilogue(serializer);
190+
page_profile_pages_written++;
191+
uv_mutex_unlock(&page_profile_lock);
192+
}
193+
}
194+
195+
void gc_page_profile_write_json_preamble(ios_t *stream) JL_NOTSAFEPOINT
196+
{
197+
if (__unlikely(page_profile_enabled)) {
198+
uv_mutex_lock(&page_profile_lock);
199+
char str[GC_TYPE_STR_MAXLEN];
200+
memset(str, 0, GC_TYPE_STR_MAXLEN);
201+
snprintf(str, GC_TYPE_STR_MAXLEN, "{");
202+
gc_page_profile_print_escape_json(stream, str, strlen(str));
203+
memset(str, 0, GC_TYPE_STR_MAXLEN);
204+
snprintf(str, GC_TYPE_STR_MAXLEN, "\"pages\": [");
205+
gc_page_profile_print_escape_json(stream, str, strlen(str));
206+
uv_mutex_unlock(&page_profile_lock);
207+
}
208+
}
209+
210+
void gc_page_profile_write_json_epilogue(ios_t *stream) JL_NOTSAFEPOINT
211+
{
212+
if (__unlikely(page_profile_enabled)) {
213+
uv_mutex_lock(&page_profile_lock);
214+
char str[GC_TYPE_STR_MAXLEN];
215+
memset(str, 0, GC_TYPE_STR_MAXLEN);
216+
snprintf(str, GC_TYPE_STR_MAXLEN, "]");
217+
gc_page_profile_print_escape_json(stream, str, strlen(str));
218+
memset(str, 0, GC_TYPE_STR_MAXLEN);
219+
snprintf(str, GC_TYPE_STR_MAXLEN, "}");
220+
gc_page_profile_print_escape_json(stream, str, strlen(str));
221+
uv_mutex_unlock(&page_profile_lock);
222+
}
223+
}
224+
225+
JL_DLLEXPORT void jl_gc_take_page_profile(ios_t *stream)
226+
{
227+
gc_enable_page_profile();
228+
page_profile_stream = stream;
229+
gc_page_profile_write_json_preamble(stream);
230+
jl_gc_collect(JL_GC_FULL);
231+
gc_page_profile_write_json_epilogue(stream);
232+
gc_disable_page_profile();
233+
}
234+
235+
#ifdef __cplusplus
236+
}
237+
#endif

src/gc-page-profiler.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
#ifndef GC_PAGE_PROFILER_H
4+
#define GC_PAGE_PROFILER_H
5+
6+
#include "gc.h"
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
#define GC_TYPE_STR_MAXLEN (512)
13+
14+
typedef struct {
15+
size_t length;
16+
size_t capacity;
17+
char const **buffer;
18+
char *data;
19+
int osize;
20+
} gc_page_profiler_serializer_t;
21+
22+
// mutex for page profile
23+
extern uv_mutex_t page_profile_lock;
24+
25+
// Serializer functions
26+
gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT;
27+
void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT;
28+
void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
29+
void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, const char *str) JL_NOTSAFEPOINT;
30+
// Page profile functions
31+
void gc_page_profile_write_preamble(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
32+
void gc_page_profile_write_epilogue(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
33+
void gc_page_profile_write_empty_page(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
34+
void gc_page_profile_write_garbage(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
35+
void gc_page_profile_write_live_obj(gc_page_profiler_serializer_t *serializer, jl_taggedvalue_t *v) JL_NOTSAFEPOINT;
36+
void gc_enable_page_profile(void) JL_NOTSAFEPOINT;
37+
void gc_disable_page_profile(void) JL_NOTSAFEPOINT;
38+
void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
39+
40+
#ifdef __cplusplus
41+
}
42+
#endif
43+
44+
#endif // GC_PAGE_PROFILER_H

0 commit comments

Comments
 (0)