]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2011 New Dream Network/Sage Weil <sage@newdream.net> | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include "acconfig.h" | |
16 | ||
17 | // Use the newer gperftools header locations if available. | |
18 | // If not, fall back to the old (gperftools < 2.0) locations. | |
19 | ||
20 | #include <gperftools/heap-profiler.h> | |
21 | #include <gperftools/malloc_extension.h> | |
22 | ||
23 | #include "heap_profiler.h" | |
24 | #include "common/environment.h" | |
25 | #include "common/LogClient.h" | |
26 | #include "global/global_context.h" | |
27 | #include "common/debug.h" | |
28 | ||
29 | #define dout_context g_ceph_context | |
30 | ||
31 | bool ceph_using_tcmalloc() | |
32 | { | |
33 | return true; | |
34 | } | |
35 | ||
36 | void ceph_heap_profiler_init() | |
37 | { | |
38 | // Two other interesting environment variables to set are: | |
39 | // HEAP_PROFILE_ALLOCATION_INTERVAL, HEAP_PROFILE_INUSE_INTERVAL | |
40 | if (get_env_bool("CEPH_HEAP_PROFILER_INIT")) { | |
41 | ceph_heap_profiler_start(); | |
42 | } | |
43 | } | |
44 | ||
45 | void ceph_heap_profiler_stats(char *buf, int length) | |
46 | { | |
47 | MallocExtension::instance()->GetStats(buf, length); | |
48 | } | |
49 | ||
50 | void ceph_heap_release_free_memory() | |
51 | { | |
52 | MallocExtension::instance()->ReleaseFreeMemory(); | |
53 | } | |
54 | ||
11fdf7f2 TL |
55 | double ceph_heap_get_release_rate() |
56 | { | |
57 | return MallocExtension::instance()->GetMemoryReleaseRate(); | |
58 | } | |
59 | ||
60 | void ceph_heap_set_release_rate(double val) | |
61 | { | |
62 | MallocExtension::instance()->SetMemoryReleaseRate(val); | |
63 | } | |
64 | ||
7c673cae FG |
65 | bool ceph_heap_get_numeric_property( |
66 | const char *property, size_t *value) | |
67 | { | |
68 | return MallocExtension::instance()->GetNumericProperty( | |
69 | property, | |
70 | value); | |
71 | } | |
72 | ||
73 | bool ceph_heap_set_numeric_property( | |
74 | const char *property, size_t value) | |
75 | { | |
76 | return MallocExtension::instance()->SetNumericProperty( | |
77 | property, | |
78 | value); | |
79 | } | |
80 | ||
81 | bool ceph_heap_profiler_running() | |
82 | { | |
83 | #ifdef HAVE_LIBTCMALLOC | |
84 | return IsHeapProfilerRunning(); | |
85 | #else | |
86 | return false; | |
87 | #endif | |
88 | } | |
89 | ||
90 | static void get_profile_name(char *profile_name, int profile_name_len) | |
91 | { | |
11fdf7f2 TL |
92 | #if __GNUC__ && __GNUC__ >= 8 |
93 | #pragma GCC diagnostic push | |
94 | // Don't care, it doesn't matter, and we can't do anything about it. | |
95 | #pragma GCC diagnostic ignored "-Wformat-truncation" | |
96 | #endif | |
97 | ||
7c673cae | 98 | char path[PATH_MAX]; |
11fdf7f2 | 99 | snprintf(path, sizeof(path), "%s", g_conf()->log_file.c_str()); |
7c673cae FG |
100 | char *last_slash = rindex(path, '/'); |
101 | ||
102 | if (last_slash == NULL) { | |
103 | snprintf(profile_name, profile_name_len, "./%s.profile", | |
11fdf7f2 | 104 | g_conf()->name.to_cstr()); |
7c673cae FG |
105 | } |
106 | else { | |
107 | last_slash[1] = '\0'; | |
108 | snprintf(profile_name, profile_name_len, "%s/%s.profile", | |
11fdf7f2 | 109 | path, g_conf()->name.to_cstr()); |
7c673cae | 110 | } |
11fdf7f2 TL |
111 | #if __GNUC__ && __GNUC__ >= 8 |
112 | #pragma GCC diagnostic pop | |
113 | #endif | |
7c673cae FG |
114 | } |
115 | ||
116 | void ceph_heap_profiler_start() | |
117 | { | |
118 | #ifdef HAVE_LIBTCMALLOC | |
119 | char profile_name[PATH_MAX]; | |
120 | get_profile_name(profile_name, sizeof(profile_name)); | |
121 | generic_dout(0) << "turning on heap profiler with prefix " | |
122 | << profile_name << dendl; | |
123 | HeapProfilerStart(profile_name); | |
124 | #endif | |
125 | } | |
126 | ||
127 | void ceph_heap_profiler_stop() | |
128 | { | |
129 | #ifdef HAVE_LIBTCMALLOC | |
130 | HeapProfilerStop(); | |
131 | #endif | |
132 | } | |
133 | ||
134 | void ceph_heap_profiler_dump(const char *reason) | |
135 | { | |
136 | #ifdef HAVE_LIBTCMALLOC | |
137 | HeapProfilerDump(reason); | |
138 | #endif | |
139 | } | |
140 | ||
141 | #define HEAP_PROFILER_STATS_SIZE 2048 | |
142 | ||
143 | void ceph_heap_profiler_handle_command(const std::vector<std::string>& cmd, | |
144 | ostream& out) | |
145 | { | |
146 | #ifdef HAVE_LIBTCMALLOC | |
147 | if (cmd.size() == 1 && cmd[0] == "dump") { | |
148 | if (!ceph_heap_profiler_running()) { | |
149 | out << "heap profiler not running; can't dump"; | |
150 | return; | |
151 | } | |
152 | char heap_stats[HEAP_PROFILER_STATS_SIZE]; | |
153 | ceph_heap_profiler_stats(heap_stats, sizeof(heap_stats)); | |
11fdf7f2 | 154 | out << g_conf()->name << " dumping heap profile now.\n" |
7c673cae FG |
155 | << heap_stats; |
156 | ceph_heap_profiler_dump("admin request"); | |
157 | } else if (cmd.size() == 1 && cmd[0] == "start_profiler") { | |
158 | ceph_heap_profiler_start(); | |
11fdf7f2 | 159 | out << g_conf()->name << " started profiler"; |
7c673cae FG |
160 | } else if (cmd.size() == 1 && cmd[0] == "stop_profiler") { |
161 | ceph_heap_profiler_stop(); | |
11fdf7f2 | 162 | out << g_conf()->name << " stopped profiler"; |
7c673cae FG |
163 | } else if (cmd.size() == 1 && cmd[0] == "release") { |
164 | ceph_heap_release_free_memory(); | |
11fdf7f2 TL |
165 | out << g_conf()->name << " releasing free RAM back to system."; |
166 | } else if (cmd.size() == 1 && cmd[0] == "get_release_rate") { | |
167 | out << g_conf()->name << " release rate: " | |
168 | << std::setprecision(4) << ceph_heap_get_release_rate() << "\n"; | |
169 | } else if (cmd.size() == 2 && cmd[0] == "set_release_rate") { | |
170 | try { | |
171 | double val = std::stod(cmd[1]); | |
172 | ceph_heap_set_release_rate(val); | |
173 | out << g_conf()->name << " release rate changed to: " | |
174 | << std::setprecision(4) << ceph_heap_get_release_rate() << "\n"; | |
175 | } catch (...) { | |
176 | out << g_conf()->name << " *** need an numerical value. "; | |
177 | } | |
7c673cae FG |
178 | } else |
179 | #endif | |
180 | if (cmd.size() == 1 && cmd[0] == "stats") { | |
181 | char heap_stats[HEAP_PROFILER_STATS_SIZE]; | |
182 | ceph_heap_profiler_stats(heap_stats, sizeof(heap_stats)); | |
11fdf7f2 | 183 | out << g_conf()->name << " tcmalloc heap stats:" |
7c673cae FG |
184 | << heap_stats; |
185 | } else { | |
186 | out << "unknown command " << cmd; | |
187 | } | |
188 | } |