github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/server/status/runtime_jemalloc.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // +build !stdmalloc 12 13 package status 14 15 // #cgo CPPFLAGS: -DJEMALLOC_NO_DEMANGLE 16 // #cgo LDFLAGS: -ljemalloc 17 // #cgo dragonfly freebsd LDFLAGS: -lm 18 // #cgo linux LDFLAGS: -lrt -lm -lpthread 19 // 20 // #include <jemalloc/jemalloc.h> 21 // 22 // // https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Introspection-Via-mallctl*() 23 // // https://github.com/jemalloc/jemalloc/blob/4.5.0/src/stats.c#L960:L969 24 // 25 // typedef struct { 26 // size_t Allocated; 27 // size_t Active; 28 // size_t Metadata; 29 // size_t Resident; 30 // size_t Mapped; 31 // size_t Retained; 32 // } JemallocStats; 33 // 34 // int jemalloc_get_stats(JemallocStats *stats) { 35 // // Update the statistics cached by je_mallctl. 36 // uint64_t epoch = 1; 37 // size_t sz = sizeof(epoch); 38 // je_mallctl("epoch", &epoch, &sz, &epoch, sz); 39 // 40 // int err; 41 // 42 // sz = sizeof(&stats->Allocated); 43 // err = je_mallctl("stats.allocated", &stats->Allocated, &sz, NULL, 0); 44 // if (err != 0) { 45 // return err; 46 // } 47 // sz = sizeof(&stats->Active); 48 // err = je_mallctl("stats.active", &stats->Active, &sz, NULL, 0); 49 // if (err != 0) { 50 // return err; 51 // } 52 // sz = sizeof(&stats->Metadata); 53 // err = je_mallctl("stats.metadata", &stats->Metadata, &sz, NULL, 0); 54 // if (err != 0) { 55 // return err; 56 // } 57 // sz = sizeof(&stats->Resident); 58 // err = je_mallctl("stats.resident", &stats->Resident, &sz, NULL, 0); 59 // if (err != 0) { 60 // return err; 61 // } 62 // sz = sizeof(&stats->Mapped); 63 // err = je_mallctl("stats.mapped", &stats->Mapped, &sz, NULL, 0); 64 // if (err != 0) { 65 // return err; 66 // } 67 // sz = sizeof(&stats->Retained); 68 // err = je_mallctl("stats.retained", &stats->Retained, &sz, NULL, 0); 69 // if (err != 0) { 70 // return err; 71 // } 72 // return err; 73 // } 74 import "C" 75 76 import ( 77 "context" 78 "math" 79 "reflect" 80 "strings" 81 82 "github.com/cockroachdb/cockroach/pkg/util/log" 83 "github.com/dustin/go-humanize" 84 ) 85 86 func init() { 87 if getCgoMemStats != nil { 88 panic("getCgoMemStats is already set") 89 } 90 getCgoMemStats = getJemallocStats 91 } 92 93 func getJemallocStats(ctx context.Context) (uint, uint, error) { 94 var js C.JemallocStats 95 // TODO(marc): should we panic here? Failure on fetching the stats may be a problem. 96 if _, err := C.jemalloc_get_stats(&js); err != nil { 97 return 0, 0, err 98 } 99 100 if log.V(2) { 101 // Summary of jemalloc stats: 102 v := reflect.ValueOf(js) 103 t := v.Type() 104 stats := make([]string, v.NumField()) 105 for i := 0; i < v.NumField(); i++ { 106 stats[i] = t.Field(i).Name + ": " + humanize.IBytes(uint64(v.Field(i).Interface().(C.size_t))) 107 } 108 log.Infof(ctx, "jemalloc stats: %s", strings.Join(stats, " ")) 109 } 110 111 // NB: the `!V(MaxInt32)` condition is a workaround to not spew this to the 112 // logs whenever log interception (log spy) is active. If we refactored 113 // je_malloc_stats_print to return a string that we can `log.Infof` instead, 114 // we wouldn't need this. 115 if log.V(3) && !log.V(math.MaxInt32) { 116 // Detailed jemalloc stats (very verbose, includes per-arena stats). 117 C.je_malloc_stats_print(nil, nil, nil) 118 } 119 120 return uint(js.Allocated), uint(js.Resident), nil 121 } 122 123 // Used to force allocation in tests. 'import "C"' is not supported in tests. 124 func allocateMemory() { 125 // Empirically, 8KiB is not enough, but 16KiB is except for ppc64le, where 256KiB is needed. 126 C.malloc(256 << 10) 127 }