|  | 
|  | 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 | +gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT | 
|  | 19 | +{ | 
|  | 20 | +    gc_page_profiler_serializer_t serializer; | 
|  | 21 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 22 | +        arraylist_new(&serializer.typestrs, GC_PAGE_SZ); | 
|  | 23 | +    } | 
|  | 24 | +    else { | 
|  | 25 | +        serializer.typestrs.len = 0; | 
|  | 26 | +    } | 
|  | 27 | +    return serializer; | 
|  | 28 | +} | 
|  | 29 | + | 
|  | 30 | +void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, | 
|  | 31 | +                             jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT | 
|  | 32 | +{ | 
|  | 33 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 34 | +        serializer->typestrs.len = 0; | 
|  | 35 | +        serializer->data = (char *)pg->data; | 
|  | 36 | +        serializer->osize = pg->osize; | 
|  | 37 | +    } | 
|  | 38 | +} | 
|  | 39 | + | 
|  | 40 | +void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT | 
|  | 41 | +{ | 
|  | 42 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 43 | +        arraylist_free(&serializer->typestrs); | 
|  | 44 | +    } | 
|  | 45 | +} | 
|  | 46 | + | 
|  | 47 | +void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, | 
|  | 48 | +                              const char *str) JL_NOTSAFEPOINT | 
|  | 49 | +{ | 
|  | 50 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 51 | +        arraylist_push(&serializer->typestrs, (void *)str); | 
|  | 52 | +    } | 
|  | 53 | +} | 
|  | 54 | + | 
|  | 55 | +void gc_enable_page_profile(void) JL_NOTSAFEPOINT | 
|  | 56 | +{ | 
|  | 57 | +    page_profile_enabled = 1; | 
|  | 58 | +} | 
|  | 59 | + | 
|  | 60 | +void gc_disable_page_profile(void) JL_NOTSAFEPOINT | 
|  | 61 | +{ | 
|  | 62 | +    page_profile_enabled = 0; | 
|  | 63 | +} | 
|  | 64 | + | 
|  | 65 | +int gc_page_profile_is_enabled(void) JL_NOTSAFEPOINT | 
|  | 66 | +{ | 
|  | 67 | +    return page_profile_enabled; | 
|  | 68 | +} | 
|  | 69 | + | 
|  | 70 | +void gc_page_profile_write_preamble(gc_page_profiler_serializer_t *serializer) | 
|  | 71 | +    JL_NOTSAFEPOINT | 
|  | 72 | +{ | 
|  | 73 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 74 | +        char str[GC_TYPE_STR_MAXLEN]; | 
|  | 75 | +        snprintf(str, GC_TYPE_STR_MAXLEN, | 
|  | 76 | +                 "{\"address\": \"%p\",\"object_size\": %d,\"objects\": [", | 
|  | 77 | +                 serializer->data, serializer->osize); | 
|  | 78 | +        ios_write(page_profile_stream, str, strlen(str)); | 
|  | 79 | +    } | 
|  | 80 | +} | 
|  | 81 | + | 
|  | 82 | +void gc_page_profile_write_epilogue(gc_page_profiler_serializer_t *serializer) | 
|  | 83 | +    JL_NOTSAFEPOINT | 
|  | 84 | +{ | 
|  | 85 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 86 | +        const char *str = "]}"; | 
|  | 87 | +        ios_write(page_profile_stream, str, strlen(str)); | 
|  | 88 | +    } | 
|  | 89 | +} | 
|  | 90 | + | 
|  | 91 | +void gc_page_profile_write_comma(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT | 
|  | 92 | +{ | 
|  | 93 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 94 | +        // write comma if not first page | 
|  | 95 | +        if (page_profile_pages_written > 0) { | 
|  | 96 | +            const char *str = ","; | 
|  | 97 | +            ios_write(page_profile_stream, str, strlen(str)); | 
|  | 98 | +        } | 
|  | 99 | +    } | 
|  | 100 | +} | 
|  | 101 | + | 
|  | 102 | +void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer) | 
|  | 103 | +    JL_NOTSAFEPOINT | 
|  | 104 | +{ | 
|  | 105 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 106 | +        // write to file | 
|  | 107 | +        uv_mutex_lock(&page_profile_lock); | 
|  | 108 | +        gc_page_profile_write_comma(serializer); | 
|  | 109 | +        gc_page_profile_write_preamble(serializer); | 
|  | 110 | +        char str[GC_TYPE_STR_MAXLEN]; | 
|  | 111 | +        for (size_t i = 0; i < serializer->typestrs.len; i++) { | 
|  | 112 | +            const char *name = (const char *)serializer->typestrs.items[i]; | 
|  | 113 | +            if (name == GC_SERIALIZER_EMPTY) { | 
|  | 114 | +                snprintf(str, GC_TYPE_STR_MAXLEN, "\"empty\","); | 
|  | 115 | +            } | 
|  | 116 | +            else if (name == GC_SERIALIZER_GARBAGE) { | 
|  | 117 | +                snprintf(str, GC_TYPE_STR_MAXLEN, "\"garbage\","); | 
|  | 118 | +            } | 
|  | 119 | +            else { | 
|  | 120 | +                snprintf(str, GC_TYPE_STR_MAXLEN, "\"%s\",", name); | 
|  | 121 | +            } | 
|  | 122 | +            // remove trailing comma for last element | 
|  | 123 | +            if (i == serializer->typestrs.len - 1) { | 
|  | 124 | +                str[strlen(str) - 1] = '\0'; | 
|  | 125 | +            } | 
|  | 126 | +            ios_write(page_profile_stream, str, strlen(str)); | 
|  | 127 | +        } | 
|  | 128 | +        gc_page_profile_write_epilogue(serializer); | 
|  | 129 | +        page_profile_pages_written++; | 
|  | 130 | +        uv_mutex_unlock(&page_profile_lock); | 
|  | 131 | +    } | 
|  | 132 | +} | 
|  | 133 | + | 
|  | 134 | +void gc_page_profile_write_json_preamble(ios_t *stream) JL_NOTSAFEPOINT | 
|  | 135 | +{ | 
|  | 136 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 137 | +        uv_mutex_lock(&page_profile_lock); | 
|  | 138 | +        const char *str = "{\"pages\": ["; | 
|  | 139 | +        ios_write(stream, str, strlen(str)); | 
|  | 140 | +        uv_mutex_unlock(&page_profile_lock); | 
|  | 141 | +    } | 
|  | 142 | +} | 
|  | 143 | + | 
|  | 144 | +void gc_page_profile_write_json_epilogue(ios_t *stream) JL_NOTSAFEPOINT | 
|  | 145 | +{ | 
|  | 146 | +    if (__unlikely(page_profile_enabled)) { | 
|  | 147 | +        uv_mutex_lock(&page_profile_lock); | 
|  | 148 | +        const char *str = "]}"; | 
|  | 149 | +        ios_write(stream, str, strlen(str)); | 
|  | 150 | +        uv_mutex_unlock(&page_profile_lock); | 
|  | 151 | +    } | 
|  | 152 | +} | 
|  | 153 | + | 
|  | 154 | +JL_DLLEXPORT void jl_gc_take_page_profile(ios_t *stream) | 
|  | 155 | +{ | 
|  | 156 | +    gc_enable_page_profile(); | 
|  | 157 | +    page_profile_pages_written = 0; | 
|  | 158 | +    page_profile_stream = stream; | 
|  | 159 | +    gc_page_profile_write_json_preamble(stream); | 
|  | 160 | +    jl_gc_collect(JL_GC_FULL); | 
|  | 161 | +    gc_page_profile_write_json_epilogue(stream); | 
|  | 162 | +    gc_disable_page_profile(); | 
|  | 163 | +} | 
|  | 164 | + | 
|  | 165 | +#ifdef __cplusplus | 
|  | 166 | +} | 
|  | 167 | +#endif | 
0 commit comments