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, ...) \
37 if (opt_v >= vv) printf(__VA_ARGS__); \
48 -V print version and exit\n\
50 --seed= random number generator seed\n\
51 --min= min alloc default=%u\n\
52 --max= max alloc default=%u\n\
54 --new use new/delete\n\
57 --threads= default=%u\n\
59 basename(argv[0]), basename(argv[0]), opt_min_alloc, opt_max_alloc, opt_ave, opt_threads
62 uint64_t opt_hi_water = 1 * (1024 * 1024 * 1024);
63 uint64_t opt_lo_water = 8 * (1024 * 1024);
64 unsigned opt_seed = 2, opt_seed_ = 1;
65 unsigned opt_max_alloc = 128 * (1024);
66 unsigned opt_min_alloc = 1 * (1024);
69 unsigned opt_ave = 100000;
74 uint64_t human(
char* optarg)
77 uint64_t ret = strtoul(optarg, &endptr, 0);
78 if (*endptr ==
'k' || *endptr ==
'K')
80 else if (*endptr ==
'm' || *endptr ==
'M')
82 else if (*endptr ==
'g' || *endptr ==
'G')
83 ret *= 1024 * 1024 * 1024;
87 void parse_args(
int argc,
char* argv[])
93 static struct option long_options[] = {
94 {
"help", no_argument, 0,
'h'},
95 {
"seed", required_argument, 0,
's'},
96 {
"hi", required_argument, 0, 1},
97 {
"lo", required_argument, 0, 2},
98 {
"min", required_argument, 0, 3},
99 {
"max", required_argument, 0, 4},
100 {
"no-seed", no_argument, 0, 5},
101 {
"ave", required_argument, 0, 6},
102 {
"threads", required_argument, 0, 7},
103 {
"time", required_argument, 0,
't'},
105 opt = getopt_long(argc, argv,
"?hvVs:t:", long_options, NULL);
106 if (opt == -1)
break;
122 opt_seed = strtoul(optarg, NULL, 0);
126 opt_time = strtoul(optarg, NULL, 0);
129 opt_hi_water = human(optarg);
132 opt_lo_water = human(optarg);
135 opt_min_alloc = human(optarg);
138 opt_max_alloc = human(optarg);
144 opt_ave = strtoul(optarg, NULL, 0);
147 opt_threads = strtoul(optarg, NULL, 0);
150 printf(
"?? getopt returned character code 0%o ??\n", opt);
156 uint64_t gettimeofday_us(
void)
159 gettimeofday(&tv, NULL);
160 return (uint64_t)tv.tv_sec * 1000000 + tv.tv_usec;
166 : count_(0), running_tot_us_(0), running_tot_MB_(0.0) {}
168 void update(
double MB, int64_t delta_us)
171 running_tot_MB_ += MB;
172 running_tot_us_ += delta_us;
173 times_per_.insert((
double)delta_us / MB);
178 void get_clear(
double& tot_MB, int64_t& tot_delta_us,
int& count,
double& min,
double& max)
181 tot_MB = running_tot_MB_;
182 tot_delta_us = running_tot_us_;
188 min = *(times_per_.begin());
189 max = *(times_per_.rbegin());
191 running_tot_MB_ = 0.0;
200 int64_t running_tot_us_;
201 double running_tot_MB_;
202 std::multiset<double> times_per_;
209 : num_mallocs(0), stats_(stats) {}
211 #define NUM_DELTAS opt_ave
217 void* malloc_opt(
unsigned* alloc_bytes)
220 if ((opt_max_alloc - opt_min_alloc) == 0)
221 *alloc_bytes = opt_max_alloc;
223 *alloc_bytes = (random() % (opt_max_alloc - opt_min_alloc)) + opt_min_alloc;
225 uint64_t t0 = gettimeofday_us();
227 ptr = malloc(*alloc_bytes);
234 for (ii = 0; ii < *alloc_bytes; ii += 4096) *(
int*)((
char*)ptr + ii) = 1;
237 int64_t delta_us = gettimeofday_us() - t0;
238 #define PAGES_PER_MB (0x100000 / 4096.0)
239 double MB = (double)ii / PAGES_PER_MB;
240 TLOG(TLVL_INFO) <<
"malloc " << *alloc_bytes <<
" bytes ii=" << ii <<
" MB=" << MB;
242 stats_.update(MB, delta_us);
248 static void do_work(Stats* stats)
250 std::vector<std::pair<void*, int>> ptr_vec;
251 uint64_t total_allocation = 0;
261 while (total_allocation < opt_lo_water)
263 unsigned alloc_bytes;
264 int8_t* ptr = (int8_t*)mm.malloc_opt(&alloc_bytes);
265 std::pair<void*, int> xx(ptr, alloc_bytes);
266 ptr_vec.push_back(xx);
267 total_allocation += alloc_bytes;
271 printf(
"ptr_vec.size()=%ld\n", ptr_vec.size());
276 long tst = (direction == up) ? RAND_MAX / 4 * 3 : RAND_MAX / 4 * 1;
277 int malloc1_or_free0 = rr < tst;
279 if (malloc1_or_free0)
282 unsigned alloc_bytes;
283 int8_t* ptr = (int8_t*)mm.malloc_opt(&alloc_bytes);
284 std::pair<void*, int> xx(ptr, alloc_bytes);
285 ptr_vec.push_back(xx);
286 total_allocation += alloc_bytes;
287 if (total_allocation > opt_hi_water && direction == up)
289 TLOG(TLVL_WARNING) <<
"direction=down";
296 if (ptr_vec.size() == 0)
298 printf(
"size()==0 - continue\n");
301 unsigned free_idx = random() % ptr_vec.size();
302 std::pair<void*, int> xx(ptr_vec[free_idx]);
303 ptr_vec.erase(ptr_vec.begin() + free_idx);
304 TLOG(TLVL_INFO) <<
"free " << xx.second;
306 total_allocation -= xx.second;
307 if (total_allocation < opt_lo_water && direction == down)
309 TLOG(TLVL_WARNING) <<
"direction=up";
316 void send_metrics(
double ave,
double min,
double max,
double MBperalloc, int32_t threads)
318 #define CLUSTER "mu2e DAQ"
319 #define GROUP "memory"
320 send_gmetric(
"ave", std::to_string(ave).c_str(),
"double",
"us/MB",
"both", 30, 0, GROUP, CLUSTER,
"ave us/MB",
322 send_gmetric(
"min", std::to_string(min).c_str(),
"double",
"us/MB",
"both", 30, 0, GROUP, CLUSTER,
"min us/MB",
324 send_gmetric(
"max", std::to_string(max).c_str(),
"double",
"us/MB",
"both", 30, 0, GROUP, CLUSTER,
"max us/MB",
326 send_gmetric(
"ave_MBperalloc", std::to_string(MBperalloc).c_str(),
"double",
"MB/alloc",
"both", 30, 0, GROUP,
327 CLUSTER,
"ave MB/alloc",
"ave MB/alloc");
328 send_gmetric(
"threads", std::to_string(threads).c_str(),
"int32",
"threads",
"both", 30, 0, GROUP, CLUSTER,
329 "threads mallocing",
"threads mallocing");
332 int main(
int argc,
char* argv[])
334 parse_args(argc, argv);
336 if (opt_hi_water < opt_lo_water)
338 printf(
"changeing hi_water from %lu to %lu\n", opt_hi_water, opt_lo_water);
339 opt_hi_water = opt_lo_water;
341 if (opt_max_alloc < opt_min_alloc)
343 printf(
"changeing max_alloc from %u to %u\n", opt_max_alloc, opt_min_alloc);
344 opt_max_alloc = opt_min_alloc;
347 if (!opt_seed_) opt_seed = time(NULL) * getpid();
349 printf(
"opt_seed=%u RAND_MAX=%d random=%ld\n", opt_seed, RAND_MAX, random());
350 printf(
"lo=%ld hi=%ld min=%u max=%u\n", opt_lo_water, opt_hi_water, opt_min_alloc, opt_max_alloc);
354 std::vector<boost::thread> threads(opt_threads);
355 std::vector<Stats> stats(opt_threads);
356 for (
auto nn = 0; nn < opt_threads; ++nn)
358 boost::thread::attributes attrs;
359 attrs.set_stack_size(4096 * 2000);
362 threads[nn] = boost::thread(attrs, boost::bind(&do_work, &stats[nn]));
364 catch (
const boost::exception& e)
366 TLOG(TLVL_ERROR) <<
"Caught boost::exception starting malloc_free thread: " << boost::diagnostic_information(e)
367 <<
", errno=" << errno;
368 std::cerr <<
"Caught boost::exception starting malloc_free thread: " << boost::diagnostic_information(e)
369 <<
", errno=" << errno << std::endl;
374 uint64_t start_us = gettimeofday_us();
375 uint64_t end_us = start_us + (1000000L * opt_time);
377 for (
auto cc = 2; 1; ++cc)
379 double tot_ave_usperMB = 0.0, tot_min_usperMB = 0.0, tot_max_usperMB = 0.0, tot_MBperalloc = 0.0;
380 for (
auto nn = 0; nn < opt_threads; ++nn)
386 stats[nn].get_clear(tot_MB, tot_us, count, min, max);
387 tot_ave_usperMB += (tot_MB != 0.0) ? (double)tot_us / tot_MB : 0.0;
388 tot_min_usperMB += min;
389 tot_max_usperMB += max;
390 tot_MBperalloc += count ? tot_MB / count : 0;
391 TLOG(6) <<
"nn=" << nn <<
" tot_MB=" << std::setprecision(4) << tot_MB <<
" count=" << count;
394 TLOG(TLVL_ERROR) << opt_threads <<
" ave malloc usec/MB ave=" << std::setprecision(4)
395 << tot_ave_usperMB / opt_threads <<
" min=" << tot_min_usperMB / opt_threads
396 <<
" max=" << tot_max_usperMB / opt_threads <<
" MB/alloc=" << std::setprecision(1)
397 << tot_MBperalloc / opt_threads;
399 send_metrics(tot_ave_usperMB / opt_threads, tot_min_usperMB / opt_threads, tot_max_usperMB / opt_threads,
400 tot_MBperalloc / opt_threads, opt_threads);
402 uint64_t target = start_us + (5000000L * cc);
403 uint64_t now_us = gettimeofday_us();
404 int64_t slp = target - now_us;
407 if ((now_us + slp) > end_us)
break;
412 printf(
"cc=%d slp=%ld\n", cc, slp);
413 if (now_us > end_us)
break;
416 send_metrics(0.0, 0.0, 0.0, 0.0, 0);
418 for (
auto nn = 0; nn < opt_threads; ++nn)
422 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.