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  }