6 static char const* rev =
"$Revision: 1.12 $$Date: 2016/11/04 13:57:24 $";
23 #include <boost/thread.hpp>
30 #define TRACE_NAME "malloc_free"
34 #define TRACE(vv, ...) \
36 if (opt_v >= vv) printf(__VA_ARGS__); \
47 -V print version and exit\n\
49 --seed= random number generator seed\n\
50 --min= min alloc default=%u\n\
51 --max= max alloc default=%u\n\
53 --new use new/delete\n\
56 --threads= default=%u\n\
58 basename(argv[0]), basename(argv[0]), opt_min_alloc, opt_max_alloc, opt_ave, opt_threads
61 uint64_t opt_hi_water = 1 * (1024 * 1024 * 1024);
62 uint64_t opt_lo_water = 8 * (1024 * 1024);
63 unsigned opt_seed = 2, opt_seed_ = 1;
64 unsigned opt_max_alloc = 128 * (1024);
65 unsigned opt_min_alloc = 1 * (1024);
68 unsigned opt_ave = 100000;
73 uint64_t human(
char* optarg) {
75 uint64_t ret = strtoul(optarg, &endptr, 0);
76 if (*endptr ==
'k' || *endptr ==
'K')
78 else if (*endptr ==
'm' || *endptr ==
'M')
80 else if (*endptr ==
'g' || *endptr ==
'G')
81 ret *= 1024 * 1024 * 1024;
85 void parse_args(
int argc,
char* argv[]) {
89 static struct option long_options[] = {
90 {
"help", no_argument, 0,
'h'},
91 {
"seed", required_argument, 0,
's'},
92 {
"hi", required_argument, 0, 1},
93 {
"lo", required_argument, 0, 2},
94 {
"min", required_argument, 0, 3},
95 {
"max", required_argument, 0, 4},
96 {
"no-seed", no_argument, 0, 5},
97 {
"ave", required_argument, 0, 6},
98 {
"threads", required_argument, 0, 7},
99 {
"time", required_argument, 0,
't'},
101 opt = getopt_long(argc, argv,
"?hvVs:t:", long_options, NULL);
102 if (opt == -1)
break;
117 opt_seed = strtoul(optarg, NULL, 0);
121 opt_time = strtoul(optarg, NULL, 0);
124 opt_hi_water = human(optarg);
127 opt_lo_water = human(optarg);
130 opt_min_alloc = human(optarg);
133 opt_max_alloc = human(optarg);
139 opt_ave = strtoul(optarg, NULL, 0);
142 opt_threads = strtoul(optarg, NULL, 0);
145 printf(
"?? getopt returned character code 0%o ??\n", opt);
151 uint64_t gettimeofday_us(
void) {
153 gettimeofday(&tv, NULL);
154 return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
158 Stats() : count_(0), running_tot_us_(0), running_tot_MB_(0.0) {}
160 void update(
double MB, int64_t delta_us) {
162 running_tot_MB_ += MB;
163 running_tot_us_ += delta_us;
164 times_per_.insert((
double)delta_us / MB);
169 void get_clear(
double& tot_MB, int64_t& tot_delta_us,
int& count,
double& min,
double& max) {
171 tot_MB = running_tot_MB_;
172 tot_delta_us = running_tot_us_;
177 min = *(times_per_.begin());
178 max = *(times_per_.rbegin());
180 running_tot_MB_ = 0.0;
189 int64_t running_tot_us_;
190 double running_tot_MB_;
191 std::multiset<double> times_per_;
196 Malloc(Stats& stats) : num_mallocs(0), stats_(stats) {}
198 #define NUM_DELTAS opt_ave
204 void* malloc_opt(
unsigned* alloc_bytes) {
206 if ((opt_max_alloc - opt_min_alloc) == 0)
207 *alloc_bytes = opt_max_alloc;
209 *alloc_bytes = (random() % (opt_max_alloc - opt_min_alloc)) + opt_min_alloc;
211 uint64_t t0 = gettimeofday_us();
213 ptr = malloc(*alloc_bytes);
219 for (ii = 0; ii < *alloc_bytes; ii += 4096) *(
int*)((
char*)ptr + ii) = 1;
222 int64_t delta_us = gettimeofday_us() - t0;
223 #define PAGES_PER_MB (0x100000 / 4096.0)
224 double MB = (double)ii / PAGES_PER_MB;
225 TLOG(TLVL_INFO) <<
"malloc " << *alloc_bytes <<
" bytes ii=" << ii <<
" MB=" << MB;
227 stats_.update(MB, delta_us);
233 static void do_work(Stats* stats) {
234 std::vector<std::pair<void*, int>> ptr_vec;
235 uint64_t total_allocation = 0;
241 while (total_allocation < opt_lo_water) {
242 unsigned alloc_bytes;
243 int8_t* ptr = (int8_t*)mm.malloc_opt(&alloc_bytes);
244 std::pair<void*, int> xx(ptr, alloc_bytes);
245 ptr_vec.push_back(xx);
246 total_allocation += alloc_bytes;
250 printf(
"ptr_vec.size()=%ld\n", ptr_vec.size());
254 long tst = (direction == up) ? RAND_MAX / 4 * 3 : RAND_MAX / 4 * 1;
255 int malloc1_or_free0 = rr < tst;
257 if (malloc1_or_free0) {
259 unsigned alloc_bytes;
260 int8_t* ptr = (int8_t*)mm.malloc_opt(&alloc_bytes);
261 std::pair<void*, int> xx(ptr, alloc_bytes);
262 ptr_vec.push_back(xx);
263 total_allocation += alloc_bytes;
264 if (total_allocation > opt_hi_water && direction == up) {
265 TLOG(TLVL_WARNING) <<
"direction=down";
270 if (ptr_vec.size() == 0) {
271 printf(
"size()==0 - continue\n");
274 unsigned free_idx = random() % ptr_vec.size();
275 std::pair<void*, int> xx(ptr_vec[free_idx]);
276 ptr_vec.erase(ptr_vec.begin() + free_idx);
277 TLOG(TLVL_INFO) <<
"free " << xx.second;
279 total_allocation -= xx.second;
280 if (total_allocation < opt_lo_water && direction == down) {
281 TLOG(TLVL_WARNING) <<
"direction=up";
288 void send_metrics(
double ave,
double min,
double max,
double MBperalloc, int32_t threads) {
289 #define CLUSTER "mu2e DAQ"
290 #define GROUP "memory"
291 send_gmetric(
"ave", std::to_string(ave).c_str(),
"double",
"us/MB",
"both", 30, 0, GROUP, CLUSTER,
"ave us/MB",
293 send_gmetric(
"min", std::to_string(min).c_str(),
"double",
"us/MB",
"both", 30, 0, GROUP, CLUSTER,
"min us/MB",
295 send_gmetric(
"max", std::to_string(max).c_str(),
"double",
"us/MB",
"both", 30, 0, GROUP, CLUSTER,
"max us/MB",
297 send_gmetric(
"ave_MBperalloc", std::to_string(MBperalloc).c_str(),
"double",
"MB/alloc",
"both", 30, 0, GROUP,
298 CLUSTER,
"ave MB/alloc",
"ave MB/alloc");
299 send_gmetric(
"threads", std::to_string(threads).c_str(),
"int32",
"threads",
"both", 30, 0, GROUP, CLUSTER,
300 "threads mallocing",
"threads mallocing");
303 int main(
int argc,
char* argv[]) {
304 parse_args(argc, argv);
306 if (opt_hi_water < opt_lo_water) {
307 printf(
"changeing hi_water from %lu to %lu\n", opt_hi_water, opt_lo_water);
308 opt_hi_water = opt_lo_water;
310 if (opt_max_alloc < opt_min_alloc) {
311 printf(
"changeing max_alloc from %u to %u\n", opt_max_alloc, opt_min_alloc);
312 opt_max_alloc = opt_min_alloc;
315 if (!opt_seed_) opt_seed = time(NULL) * getpid();
317 printf(
"opt_seed=%u RAND_MAX=%d random=%ld\n", opt_seed, RAND_MAX, random());
318 printf(
"lo=%ld hi=%ld min=%u max=%u\n", opt_lo_water, opt_hi_water, opt_min_alloc, opt_max_alloc);
322 std::vector<boost::thread> threads(opt_threads);
323 std::vector<Stats> stats(opt_threads);
324 for (
auto nn = 0; nn < opt_threads; ++nn) {
325 boost::thread::attributes attrs;
326 attrs.set_stack_size(4096 * 2000);
328 threads[nn] = boost::thread(attrs, boost::bind(&do_work, &stats[nn]));
329 }
catch (
const boost::exception& e) {
330 TLOG(TLVL_ERROR) <<
"Caught boost::exception starting malloc_free thread: " << boost::diagnostic_information(e)
331 <<
", errno=" << errno;
332 std::cerr <<
"Caught boost::exception starting malloc_free thread: " << boost::diagnostic_information(e)
333 <<
", errno=" << errno << std::endl;
338 uint64_t start_us = gettimeofday_us();
339 uint64_t end_us = start_us + (1000000L * opt_time);
341 for (
auto cc = 2; 1; ++cc) {
342 double tot_ave_usperMB = 0.0, tot_min_usperMB = 0.0, tot_max_usperMB = 0.0, tot_MBperalloc = 0.0;
343 for (
auto nn = 0; nn < opt_threads; ++nn) {
348 stats[nn].get_clear(tot_MB, tot_us, count, min, max);
349 tot_ave_usperMB += (tot_MB != 0.0) ? (double)tot_us / tot_MB : 0.0;
350 tot_min_usperMB += min;
351 tot_max_usperMB += max;
352 tot_MBperalloc += count ? tot_MB / count : 0;
353 TLOG(6) <<
"nn=" << nn <<
" tot_MB=" << std::setprecision(4) << tot_MB <<
" count=" << count;
356 TLOG(TLVL_ERROR) << opt_threads <<
" ave malloc usec/MB ave=" << std::setprecision(4)
357 << tot_ave_usperMB / opt_threads <<
" min=" << tot_min_usperMB / opt_threads
358 <<
" max=" << tot_max_usperMB / opt_threads <<
" MB/alloc=" << std::setprecision(1)
359 << tot_MBperalloc / opt_threads;
361 send_metrics(tot_ave_usperMB / opt_threads, tot_min_usperMB / opt_threads, tot_max_usperMB / opt_threads,
362 tot_MBperalloc / opt_threads, opt_threads);
364 uint64_t target = start_us + (5000000L * cc);
365 uint64_t now_us = gettimeofday_us();
366 int64_t slp = target - now_us;
368 if ((now_us + slp) > end_us)
break;
371 printf(
"cc=%d slp=%ld\n", cc, slp);
372 if (now_us > end_us)
break;
375 send_metrics(0.0, 0.0, 0.0, 0.0, 0);
377 for (
auto nn = 0; nn < opt_threads; ++nn) {
380 printf(
"malloc_free finished.\n");
int init_gmetric(const char *conf)
Initialize Ganglia.
int send_gmetric(const char *name, const char *value, const char *type, const char *units, const char *slope, int tmax, int dmax, const char *group, const char *cluster, const char *desc, const char *title)
Send a metric to gmond.